Merge "Revert "Force-enable hardware acceleration for apps""
diff --git a/Android.mk b/Android.mk
index 33e64d0..e1c15470 100644
--- a/Android.mk
+++ b/Android.mk
@@ -85,6 +85,8 @@
 	core/java/android/app/IWallpaperManager.aidl \
 	core/java/android/app/IWallpaperManagerCallback.aidl \
 	core/java/android/app/admin/IDevicePolicyManager.aidl \
+	core/java/android/app/trust/ITrustManager.aidl \
+	core/java/android/app/trust/ITrustListener.aidl \
 	core/java/android/app/backup/IBackupManager.aidl \
 	core/java/android/app/backup/IFullBackupRestoreObserver.aidl \
 	core/java/android/app/backup/IRestoreObserver.aidl \
@@ -120,6 +122,7 @@
 	core/java/android/content/pm/IPackageDataObserver.aidl \
 	core/java/android/content/pm/IPackageDeleteObserver.aidl \
 	core/java/android/content/pm/IPackageInstallObserver.aidl \
+	core/java/android/content/pm/IPackageInstallObserver2.aidl \
 	core/java/android/content/pm/IPackageManager.aidl \
 	core/java/android/content/pm/IPackageMoveObserver.aidl \
 	core/java/android/content/pm/IPackageStatsObserver.aidl \
@@ -189,6 +192,8 @@
 	core/java/android/service/dreams/IDozeHardware.aidl \
 	core/java/android/service/dreams/IDreamManager.aidl \
 	core/java/android/service/dreams/IDreamService.aidl \
+	core/java/android/service/trust/ITrustAgentService.aidl \
+	core/java/android/service/trust/ITrustAgentServiceCallback.aidl \
 	core/java/android/service/wallpaper/IWallpaperConnection.aidl \
 	core/java/android/service/wallpaper/IWallpaperEngine.aidl \
 	core/java/android/service/wallpaper/IWallpaperService.aidl \
@@ -288,6 +293,7 @@
 	telephony/java/com/android/internal/telephony/ISms.aidl \
 	telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
 	wifi/java/android/net/wifi/IWifiManager.aidl \
+	wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl \
 	wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
 	packages/services/PacProcessor/com/android/net/IProxyService.aidl \
 	packages/services/Proxy/com/android/net/IProxyCallback.aidl \
diff --git a/api/current.txt b/api/current.txt
index faeab39..efadf77 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28,6 +28,7 @@
     field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
     field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
     field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
+    field public static final java.lang.String BIND_TRUST_AGENT_SERVICE = "android.permission.BIND_TRUST_AGENT_SERVICE";
     field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
     field public static final java.lang.String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
     field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
@@ -1759,13 +1760,13 @@
     field public static final int TextAppearance_DeviceDefault_Widget = 16974265; // 0x10301b9
     field public static final int TextAppearance_DeviceDefault_Widget_ActionBar_Menu = 16974286; // 0x10301ce
     field public static final int TextAppearance_DeviceDefault_Widget_ActionBar_Subtitle = 16974279; // 0x10301c7
-    field public static final int TextAppearance_DeviceDefault_Widget_ActionBar_Subtitle_Inverse = 16974283; // 0x10301cb
+    field public static final deprecated int TextAppearance_DeviceDefault_Widget_ActionBar_Subtitle_Inverse = 16974283; // 0x10301cb
     field public static final int TextAppearance_DeviceDefault_Widget_ActionBar_Title = 16974278; // 0x10301c6
-    field public static final int TextAppearance_DeviceDefault_Widget_ActionBar_Title_Inverse = 16974282; // 0x10301ca
+    field public static final deprecated int TextAppearance_DeviceDefault_Widget_ActionBar_Title_Inverse = 16974282; // 0x10301ca
     field public static final int TextAppearance_DeviceDefault_Widget_ActionMode_Subtitle = 16974281; // 0x10301c9
-    field public static final int TextAppearance_DeviceDefault_Widget_ActionMode_Subtitle_Inverse = 16974285; // 0x10301cd
+    field public static final deprecated int TextAppearance_DeviceDefault_Widget_ActionMode_Subtitle_Inverse = 16974285; // 0x10301cd
     field public static final int TextAppearance_DeviceDefault_Widget_ActionMode_Title = 16974280; // 0x10301c8
-    field public static final int TextAppearance_DeviceDefault_Widget_ActionMode_Title_Inverse = 16974284; // 0x10301cc
+    field public static final deprecated int TextAppearance_DeviceDefault_Widget_ActionMode_Title_Inverse = 16974284; // 0x10301cc
     field public static final int TextAppearance_DeviceDefault_Widget_Button = 16974266; // 0x10301ba
     field public static final int TextAppearance_DeviceDefault_Widget_DropDownHint = 16974271; // 0x10301bf
     field public static final int TextAppearance_DeviceDefault_Widget_DropDownItem = 16974272; // 0x10301c0
@@ -2047,18 +2048,18 @@
     field public static final int Widget_DeviceDefault_Light = 16974196; // 0x1030174
     field public static final int Widget_DeviceDefault_Light_ActionBar = 16974243; // 0x10301a3
     field public static final int Widget_DeviceDefault_Light_ActionBar_Solid = 16974247; // 0x10301a7
-    field public static final int Widget_DeviceDefault_Light_ActionBar_Solid_Inverse = 16974248; // 0x10301a8
+    field public static final deprecated int Widget_DeviceDefault_Light_ActionBar_Solid_Inverse = 16974248; // 0x10301a8
     field public static final int Widget_DeviceDefault_Light_ActionBar_TabBar = 16974246; // 0x10301a6
-    field public static final int Widget_DeviceDefault_Light_ActionBar_TabBar_Inverse = 16974249; // 0x10301a9
+    field public static final deprecated int Widget_DeviceDefault_Light_ActionBar_TabBar_Inverse = 16974249; // 0x10301a9
     field public static final int Widget_DeviceDefault_Light_ActionBar_TabText = 16974245; // 0x10301a5
-    field public static final int Widget_DeviceDefault_Light_ActionBar_TabText_Inverse = 16974251; // 0x10301ab
+    field public static final deprecated int Widget_DeviceDefault_Light_ActionBar_TabText_Inverse = 16974251; // 0x10301ab
     field public static final int Widget_DeviceDefault_Light_ActionBar_TabView = 16974244; // 0x10301a4
-    field public static final int Widget_DeviceDefault_Light_ActionBar_TabView_Inverse = 16974250; // 0x10301aa
+    field public static final deprecated int Widget_DeviceDefault_Light_ActionBar_TabView_Inverse = 16974250; // 0x10301aa
     field public static final int Widget_DeviceDefault_Light_ActionButton = 16974239; // 0x103019f
     field public static final int Widget_DeviceDefault_Light_ActionButton_CloseMode = 16974242; // 0x10301a2
     field public static final int Widget_DeviceDefault_Light_ActionButton_Overflow = 16974240; // 0x10301a0
     field public static final int Widget_DeviceDefault_Light_ActionMode = 16974241; // 0x10301a1
-    field public static final int Widget_DeviceDefault_Light_ActionMode_Inverse = 16974252; // 0x10301ac
+    field public static final deprecated int Widget_DeviceDefault_Light_ActionMode_Inverse = 16974252; // 0x10301ac
     field public static final int Widget_DeviceDefault_Light_AutoCompleteTextView = 16974203; // 0x103017b
     field public static final int Widget_DeviceDefault_Light_Button = 16974197; // 0x1030175
     field public static final int Widget_DeviceDefault_Light_Button_Borderless_Small = 16974201; // 0x1030179
@@ -2186,6 +2187,7 @@
     field public static final int Widget_Holo_Light_ActionMode_Inverse = 16974119; // 0x1030127
     field public static final int Widget_Holo_Light_AutoCompleteTextView = 16974011; // 0x10300bb
     field public static final int Widget_Holo_Light_Button = 16974006; // 0x10300b6
+    field public static final int Widget_Holo_Light_Button_Borderless = 16974538; // 0x10302ca
     field public static final int Widget_Holo_Light_Button_Borderless_Small = 16974107; // 0x103011b
     field public static final int Widget_Holo_Light_Button_Inset = 16974008; // 0x10300b8
     field public static final int Widget_Holo_Light_Button_Small = 16974007; // 0x10300b7
@@ -6489,6 +6491,7 @@
     field public static final java.lang.String USER_SERVICE = "user";
     field public static final java.lang.String VIBRATOR_SERVICE = "vibrator";
     field public static final java.lang.String WALLPAPER_SERVICE = "wallpaper";
+    field public static final java.lang.String WIFI_HOTSPOT_SERVICE = "wifihotspot";
     field public static final java.lang.String WIFI_P2P_SERVICE = "wifip2p";
     field public static final java.lang.String WIFI_SERVICE = "wifi";
     field public static final java.lang.String WINDOW_SERVICE = "window";
@@ -6920,6 +6923,7 @@
     field public static final java.lang.String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
     field public static final java.lang.String CATEGORY_LE_DESK_DOCK = "android.intent.category.LE_DESK_DOCK";
     field public static final java.lang.String CATEGORY_MONKEY = "android.intent.category.MONKEY";
+    field public static final java.lang.String CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
     field public static final java.lang.String CATEGORY_OPENABLE = "android.intent.category.OPENABLE";
     field public static final java.lang.String CATEGORY_PREFERENCE = "android.intent.category.PREFERENCE";
     field public static final java.lang.String CATEGORY_SAMPLE_CODE = "android.intent.category.SAMPLE_CODE";
@@ -16198,6 +16202,19 @@
 
 }
 
+package android.net.wifi.hotspot {
+
+  public abstract interface IWifiHotspotManager implements android.os.IInterface {
+    method public abstract void test() throws android.os.RemoteException;
+  }
+
+  public class WifiHotspotManager {
+    ctor public WifiHotspotManager(android.content.Context, android.net.wifi.hotspot.IWifiHotspotManager);
+    method public void test();
+  }
+
+}
+
 package android.net.wifi.p2p {
 
   public class WifiP2pConfig implements android.os.Parcelable {
@@ -24317,8 +24334,12 @@
     ctor public NotificationListenerService();
     method public final void cancelAllNotifications();
     method public final void cancelNotification(java.lang.String, java.lang.String, int);
+    method public final void cancelNotifications(java.lang.String[]);
+    method public java.lang.String[] getActiveNotificationKeys();
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
+    method public android.service.notification.StatusBarNotification[] getActiveNotifications(java.lang.String[]);
     method public android.os.IBinder onBind(android.content.Intent);
+    method public void onListenerConnected(java.lang.String[]);
     method public abstract void onNotificationPosted(android.service.notification.StatusBarNotification);
     method public abstract void onNotificationRemoved(android.service.notification.StatusBarNotification);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
@@ -24330,6 +24351,7 @@
     method public android.service.notification.StatusBarNotification clone();
     method public int describeContents();
     method public int getId();
+    method public java.lang.String getKey();
     method public android.app.Notification getNotification();
     method public java.lang.String getPackageName();
     method public long getPostTime();
@@ -24366,6 +24388,20 @@
 
 }
 
+package android.service.trust {
+
+  public class TrustAgentService extends android.app.Service {
+    ctor public TrustAgentService();
+    method protected final void enableTrust(java.lang.String, long, boolean);
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method protected void onUnlockAttempt(boolean);
+    method protected final void revokeTrust();
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.trust.TrustAgentService";
+    field public static final java.lang.String TRUST_AGENT_META_DATA = "android.service.trust.trustagent";
+  }
+
+}
+
 package android.service.wallpaper {
 
   public abstract class WallpaperService extends android.app.Service {
@@ -27818,9 +27854,9 @@
     field public static final java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
     field public static final java.util.regex.Pattern IP_ADDRESS;
     field public static final java.util.regex.Pattern PHONE;
-    field public static final java.util.regex.Pattern TOP_LEVEL_DOMAIN;
-    field public static final java.lang.String TOP_LEVEL_DOMAIN_STR = "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(biz|b[abdefghijmnorstvwyz])|(cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(edu|e[cegrstu])|f[ijkmor]|(gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(info|int|i[delmnoqrst])|(jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(name|net|n[acefgilopruz])|(org|om)|(pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(\u03b4\u03bf\u03ba\u03b9\u03bc\u03ae|\u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u0435|\u0440\u0444|\u0441\u0440\u0431|\u05d8\u05e2\u05e1\u05d8|\u0622\u0632\u0645\u0627\u06cc\u0634\u06cc|\u0625\u062e\u062a\u0628\u0627\u0631|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633|\u0633\u0648\u0631\u064a\u0629|\u0641\u0644\u0633\u0637\u064a\u0646|\u0642\u0637\u0631|\u0645\u0635\u0631|\u092a\u0930\u0940\u0915\u094d\u0937\u093e|\u092d\u093e\u0930\u0924|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd|\u0baa\u0bb0\u0bbf\u0b9f\u0bcd\u0b9a\u0bc8|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e44\u0e17\u0e22|\u30c6\u30b9\u30c8|\u4e2d\u56fd|\u4e2d\u570b|\u53f0\u6e7e|\u53f0\u7063|\u65b0\u52a0\u5761|\u6d4b\u8bd5|\u6e2c\u8a66|\u9999\u6e2f|\ud14c\uc2a4\ud2b8|\ud55c\uad6d|xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-3e0b707e|xn\\-\\-45brj9c|xn\\-\\-80akhbyknj4f|xn\\-\\-90a3ac|xn\\-\\-9t4b11yi5a|xn\\-\\-clchc0ea0b2g2a9gcd|xn\\-\\-deba0ad|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-g6w251d|xn\\-\\-gecrj9c|xn\\-\\-h2brj9c|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-j6w193g|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-kprw13d|xn\\-\\-kpry57d|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1ai|xn\\-\\-pgbs0dh|xn\\-\\-s9brj9c|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-yfro4i67o|xn\\-\\-ygbi2ammx|xn\\-\\-zckzah|xxx)|y[et]|z[amw])";
-    field public static final java.lang.String TOP_LEVEL_DOMAIN_STR_FOR_WEB_URL = "(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(?:\u03b4\u03bf\u03ba\u03b9\u03bc\u03ae|\u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u0435|\u0440\u0444|\u0441\u0440\u0431|\u05d8\u05e2\u05e1\u05d8|\u0622\u0632\u0645\u0627\u06cc\u0634\u06cc|\u0625\u062e\u062a\u0628\u0627\u0631|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633|\u0633\u0648\u0631\u064a\u0629|\u0641\u0644\u0633\u0637\u064a\u0646|\u0642\u0637\u0631|\u0645\u0635\u0631|\u092a\u0930\u0940\u0915\u094d\u0937\u093e|\u092d\u093e\u0930\u0924|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd|\u0baa\u0bb0\u0bbf\u0b9f\u0bcd\u0b9a\u0bc8|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e44\u0e17\u0e22|\u30c6\u30b9\u30c8|\u4e2d\u56fd|\u4e2d\u570b|\u53f0\u6e7e|\u53f0\u7063|\u65b0\u52a0\u5761|\u6d4b\u8bd5|\u6e2c\u8a66|\u9999\u6e2f|\ud14c\uc2a4\ud2b8|\ud55c\uad6d|xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-3e0b707e|xn\\-\\-45brj9c|xn\\-\\-80akhbyknj4f|xn\\-\\-90a3ac|xn\\-\\-9t4b11yi5a|xn\\-\\-clchc0ea0b2g2a9gcd|xn\\-\\-deba0ad|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-g6w251d|xn\\-\\-gecrj9c|xn\\-\\-h2brj9c|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-j6w193g|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-kprw13d|xn\\-\\-kpry57d|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1ai|xn\\-\\-pgbs0dh|xn\\-\\-s9brj9c|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-yfro4i67o|xn\\-\\-ygbi2ammx|xn\\-\\-zckzah|xxx)|y[et]|z[amw]))";
+    field public static final deprecated java.util.regex.Pattern TOP_LEVEL_DOMAIN;
+    field public static final deprecated java.lang.String TOP_LEVEL_DOMAIN_STR = "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(biz|b[abdefghijmnorstvwyz])|(cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(edu|e[cegrstu])|f[ijkmor]|(gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(info|int|i[delmnoqrst])|(jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(name|net|n[acefgilopruz])|(org|om)|(pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(\u03b4\u03bf\u03ba\u03b9\u03bc\u03ae|\u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u0435|\u0440\u0444|\u0441\u0440\u0431|\u05d8\u05e2\u05e1\u05d8|\u0622\u0632\u0645\u0627\u06cc\u0634\u06cc|\u0625\u062e\u062a\u0628\u0627\u0631|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633|\u0633\u0648\u0631\u064a\u0629|\u0641\u0644\u0633\u0637\u064a\u0646|\u0642\u0637\u0631|\u0645\u0635\u0631|\u092a\u0930\u0940\u0915\u094d\u0937\u093e|\u092d\u093e\u0930\u0924|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd|\u0baa\u0bb0\u0bbf\u0b9f\u0bcd\u0b9a\u0bc8|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e44\u0e17\u0e22|\u30c6\u30b9\u30c8|\u4e2d\u56fd|\u4e2d\u570b|\u53f0\u6e7e|\u53f0\u7063|\u65b0\u52a0\u5761|\u6d4b\u8bd5|\u6e2c\u8a66|\u9999\u6e2f|\ud14c\uc2a4\ud2b8|\ud55c\uad6d|xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-3e0b707e|xn\\-\\-45brj9c|xn\\-\\-80akhbyknj4f|xn\\-\\-90a3ac|xn\\-\\-9t4b11yi5a|xn\\-\\-clchc0ea0b2g2a9gcd|xn\\-\\-deba0ad|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-g6w251d|xn\\-\\-gecrj9c|xn\\-\\-h2brj9c|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-j6w193g|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-kprw13d|xn\\-\\-kpry57d|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1ai|xn\\-\\-pgbs0dh|xn\\-\\-s9brj9c|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-yfro4i67o|xn\\-\\-ygbi2ammx|xn\\-\\-zckzah|xxx)|y[et]|z[amw])";
+    field public static final deprecated java.lang.String TOP_LEVEL_DOMAIN_STR_FOR_WEB_URL = "(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(?:\u03b4\u03bf\u03ba\u03b9\u03bc\u03ae|\u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u0435|\u0440\u0444|\u0441\u0440\u0431|\u05d8\u05e2\u05e1\u05d8|\u0622\u0632\u0645\u0627\u06cc\u0634\u06cc|\u0625\u062e\u062a\u0628\u0627\u0631|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633|\u0633\u0648\u0631\u064a\u0629|\u0641\u0644\u0633\u0637\u064a\u0646|\u0642\u0637\u0631|\u0645\u0635\u0631|\u092a\u0930\u0940\u0915\u094d\u0937\u093e|\u092d\u093e\u0930\u0924|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd|\u0baa\u0bb0\u0bbf\u0b9f\u0bcd\u0b9a\u0bc8|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e44\u0e17\u0e22|\u30c6\u30b9\u30c8|\u4e2d\u56fd|\u4e2d\u570b|\u53f0\u6e7e|\u53f0\u7063|\u65b0\u52a0\u5761|\u6d4b\u8bd5|\u6e2c\u8a66|\u9999\u6e2f|\ud14c\uc2a4\ud2b8|\ud55c\uad6d|xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-3e0b707e|xn\\-\\-45brj9c|xn\\-\\-80akhbyknj4f|xn\\-\\-90a3ac|xn\\-\\-9t4b11yi5a|xn\\-\\-clchc0ea0b2g2a9gcd|xn\\-\\-deba0ad|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-g6w251d|xn\\-\\-gecrj9c|xn\\-\\-h2brj9c|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-j6w193g|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-kprw13d|xn\\-\\-kpry57d|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1ai|xn\\-\\-pgbs0dh|xn\\-\\-s9brj9c|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-yfro4i67o|xn\\-\\-ygbi2ammx|xn\\-\\-zckzah|xxx)|y[et]|z[amw]))";
     field public static final java.util.regex.Pattern WEB_URL;
   }
 
@@ -28293,6 +28329,7 @@
     method public android.os.Vibrator getVibrator();
     method public boolean[] hasKeys(int...);
     method public boolean isVirtual();
+    method public boolean supportsSource(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int KEYBOARD_TYPE_ALPHABETIC = 2; // 0x2
@@ -29313,6 +29350,7 @@
     method protected int computeVerticalScrollRange();
     method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo();
     method public void createContextMenu(android.view.ContextMenu);
+    method public final android.animation.ValueAnimator createRevealAnimator(int, int, float, float);
     method public void destroyDrawingCache();
     method public android.view.WindowInsets dispatchApplyWindowInsets(android.view.WindowInsets);
     method public void dispatchConfigurationChanged(android.content.res.Configuration);
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
index cb7e1a0..7c25354 100644
--- a/cmds/app_process/Android.mk
+++ b/cmds/app_process/Android.mk
@@ -14,30 +14,11 @@
 	libandroid_runtime
 
 LOCAL_MODULE:= app_process
-LOCAL_32_BIT_ONLY := true
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := app_process
+LOCAL_MODULE_STEM_64 := app_process64
 include $(BUILD_EXECUTABLE)
 
-ifeq ($(TARGET_IS_64_BIT),true)
-
-# 64-bit app_process64
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	app_main.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	libutils \
-	liblog \
-	libbinder \
-	libandroid_runtime
-
-LOCAL_MODULE:= app_process64
-LOCAL_NO_2ND_ARCH := true
-include $(BUILD_EXECUTABLE)
-
-endif # TARGET_IS_64_BIT
-
 # Build a variant of app_process binary linked with ASan runtime.
 # ARM-only at the moment.
 ifeq ($(TARGET_ARCH),arm)
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index d513a10..5454b46 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -25,7 +25,7 @@
 import android.content.pm.FeatureInfo;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageDeleteObserver;
-import android.content.pm.IPackageInstallObserver;
+import android.content.pm.IPackageInstallObserver2;
 import android.content.pm.IPackageManager;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
@@ -39,6 +39,7 @@
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.IUserManager;
 import android.os.Process;
 import android.os.RemoteException;
@@ -700,14 +701,23 @@
         ActivityManager.dumpPackageStateStatic(FileDescriptor.out, pkg);
     }
 
-    class PackageInstallObserver extends IPackageInstallObserver.Stub {
+    class PackageInstallObserver extends IPackageInstallObserver2.Stub {
         boolean finished;
         int result;
+        String extraPermission;
+        String extraPackage;
 
-        public void packageInstalled(String name, int status) {
+        @Override
+        public void packageInstalled(String name, Bundle extras, int status) {
             synchronized( this) {
                 finished = true;
                 result = status;
+                if (status == PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION) {
+                    extraPermission = extras.getString(
+                            PackageManager.EXTRA_FAILURE_EXISTING_PERMISSION);
+                    extraPackage = extras.getString(
+                            PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
+                }
                 notifyAll();
             }
         }
@@ -717,7 +727,8 @@
      * Converts a failure code into a string by using reflection to find a matching constant
      * in PackageManager.
      */
-    private String installFailureToString(int result) {
+    private String installFailureToString(PackageInstallObserver obs) {
+        final int result = obs.result;
         Field[] fields = PackageManager.class.getFields();
         for (Field f: fields) {
             if (f.getType() == int.class) {
@@ -732,7 +743,16 @@
                         // get the int value and compare it to result.
                         try {
                             if (result == f.getInt(null)) {
-                                return fieldName;
+                                StringBuilder sb = new StringBuilder(64);
+                                sb.append(fieldName);
+                                if (obs.extraPermission != null) {
+                                    sb.append(" perm=");
+                                    sb.append(obs.extraPermission);
+                                }
+                                if (obs.extraPackage != null) {
+                                    sb.append(" pkg=" + obs.extraPackage);
+                                }
+                                return sb.toString();
                             }
                         } catch (IllegalAccessException e) {
                             // this shouldn't happen since we only look for public static fields.
@@ -956,7 +976,7 @@
             VerificationParams verificationParams = new VerificationParams(verificationURI,
                     originatingURI, referrerURI, VerificationParams.NO_UID, null);
 
-            mPm.installPackageWithVerificationAndEncryption(apkURI, obs, installFlags,
+            mPm.installPackageWithVerificationAndEncryptionEtc(apkURI, null, obs, installFlags,
                     installerPackageName, verificationParams, encryptionParams);
 
             synchronized (obs) {
@@ -970,7 +990,7 @@
                     System.out.println("Success");
                 } else {
                     System.err.println("Failure ["
-                            + installFailureToString(obs.result)
+                            + installFailureToString(obs)
                             + "]");
                 }
             }
@@ -1013,18 +1033,18 @@
 
     public void runCreateUser() {
         String name;
-        int relatedUserId = -1;
+        int userId = -1;
         int flags = 0;
         String opt;
         while ((opt = nextOption()) != null) {
-            if ("--relatedTo".equals(opt)) {
+            if ("--profileOf".equals(opt)) {
                 String optionData = nextOptionData();
                 if (optionData == null || !isNumber(optionData)) {
                     System.err.println("Error: no USER_ID specified");
                     showUsage();
                     return;
                 } else {
-                    relatedUserId = Integer.parseInt(optionData);
+                    userId = Integer.parseInt(optionData);
                 }
             } else if ("--managed".equals(opt)) {
                 flags |= UserInfo.FLAG_MANAGED_PROFILE;
@@ -1042,14 +1062,14 @@
         name = arg;
         try {
             UserInfo info = null;
-            if (relatedUserId < 0) {
+            if (userId < 0) {
                 info = mUm.createUser(name, flags);
             } else {
                 if (Process.myUid() != 0) {
                     System.err.println("Error: not running as root.");
                     return;
                 }
-                info = mUm.createRelatedUser(name, flags, relatedUserId);
+                info = mUm.createProfileForUser(name, flags, userId);
             }
             if (info != null) {
                 System.out.println("Success: created user id " + info.id);
diff --git a/core/java/android/alsa/AlsaCardsParser.java b/core/java/android/alsa/AlsaCardsParser.java
new file mode 100644
index 0000000..f9af979
--- /dev/null
+++ b/core/java/android/alsa/AlsaCardsParser.java
@@ -0,0 +1,116 @@
+/*
+ * 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.alsascan;
+
+import android.util.Slog;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Vector;
+
+/**
+ * @hide Retrieves information from an ALSA "cards" file.
+ */
+public class AlsaCardsParser {
+    private static final String TAG = "AlsaCardsParser";
+
+    private static LineTokenizer tokenizer_ = new LineTokenizer(" :[]");
+
+    public class AlsaCardRecord {
+        public int mCardNum = -1;
+        public String mField1 = "";
+        public String mCardName = "";
+        public String mCardDescription = "";
+
+        public AlsaCardRecord() {}
+
+        public boolean parse(String line, int lineIndex) {
+            int tokenIndex = 0;
+            int delimIndex = 0;
+            if (lineIndex == 0) {
+                // line # (skip)
+                tokenIndex = tokenizer_.nextToken(line, tokenIndex);
+                delimIndex = tokenizer_.nextDelimiter(line, tokenIndex);
+
+                // mField1
+                tokenIndex = tokenizer_.nextToken(line, delimIndex);
+                delimIndex = tokenizer_.nextDelimiter(line, tokenIndex);
+                mField1 = line.substring(tokenIndex, delimIndex);
+
+                // mCardName
+                tokenIndex = tokenizer_.nextToken(line, delimIndex);
+                // delimIndex = tokenizer_.nextDelimiter(line, tokenIndex);
+                mCardName = line.substring(tokenIndex);
+                // done
+              } else if (lineIndex == 1) {
+                  tokenIndex = tokenizer_.nextToken(line, 0);
+                  if (tokenIndex != -1) {
+                      mCardDescription = line.substring(tokenIndex);
+                  }
+            }
+
+            return true;
+        }
+
+        public String textFormat() {
+          return mCardName + " : " + mCardDescription;
+        }
+    }
+
+    private Vector<AlsaCardRecord> cardRecords_ = new Vector<AlsaCardRecord>();
+
+    public void scan() {
+          cardRecords_.clear();
+          final String cardsFilePath = "/proc/asound/cards";
+          File cardsFile = new File(cardsFilePath);
+          try {
+              FileReader reader = new FileReader(cardsFile);
+              BufferedReader bufferedReader = new BufferedReader(reader);
+              String line = "";
+              while ((line = bufferedReader.readLine()) != null) {
+                  AlsaCardRecord cardRecord = new AlsaCardRecord();
+                  cardRecord.parse(line, 0);
+                  cardRecord.parse(line = bufferedReader.readLine(), 1);
+                  cardRecords_.add(cardRecord);
+              }
+              reader.close();
+          } catch (FileNotFoundException e) {
+              e.printStackTrace();
+          } catch (IOException e) {
+              e.printStackTrace();
+          }
+      }
+
+      public AlsaCardRecord getCardRecordAt(int index) {
+          return cardRecords_.get(index);
+      }
+
+      public int getNumCardRecords() {
+          return cardRecords_.size();
+      }
+
+    public void Log() {
+      int numCardRecs = getNumCardRecords();
+      for (int index = 0; index < numCardRecs; ++index) {
+          Slog.w(TAG, "usb:" + getCardRecordAt(index).textFormat());
+      }
+    }
+
+    public AlsaCardsParser() {}
+}
diff --git a/core/java/android/alsa/AlsaDevicesParser.java b/core/java/android/alsa/AlsaDevicesParser.java
new file mode 100644
index 0000000..3835942
--- /dev/null
+++ b/core/java/android/alsa/AlsaDevicesParser.java
@@ -0,0 +1,240 @@
+/*
+ * 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.alsascan;
+
+import android.util.Slog;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Vector;
+
+/**
+ * @hide
+ * Retrieves information from an ALSA "devices" file.
+ */
+public class AlsaDevicesParser {
+    private static final String TAG = "AlsaDevicesParser";
+
+    private static final int kIndex_CardDeviceField = 5;
+    private static final int kStartIndex_CardNum = 6;
+    private static final int kEndIndex_CardNum = 8; // one past
+    private static final int kStartIndex_DeviceNum = 9;
+    private static final int kEndIndex_DeviceNum = 11; // one past
+    private static final int kStartIndex_Type = 14;
+
+    private static LineTokenizer mTokenizer = new LineTokenizer(" :[]-");
+
+    private boolean mHasCaptureDevices = false;
+    private boolean mHasPlaybackDevices = false;
+    private boolean mHasMIDIDevices = false;
+
+    public class AlsaDeviceRecord {
+        public static final int kDeviceType_Unknown = -1;
+        public static final int kDeviceType_Audio = 0;
+        public static final int kDeviceType_Control = 1;
+        public static final int kDeviceType_MIDI = 2;
+
+        public static final int kDeviceDir_Unknown = -1;
+        public static final int kDeviceDir_Capture = 0;
+        public static final int kDeviceDir_Playback = 1;
+
+        int mCardNum = -1;
+        int mDeviceNum = -1;
+        int mDeviceType = kDeviceType_Unknown;
+        int mDeviceDir = kDeviceDir_Unknown;
+
+        public AlsaDeviceRecord() {
+        }
+
+        public boolean parse(String line) {
+            // "0123456789012345678901234567890"
+            // "  2: [ 0-31]: digital audio playback"
+            // "  3: [ 0-30]: digital audio capture"
+            // " 35: [ 1]   : control"
+            // " 36: [ 2- 0]: raw midi"
+
+            final int kToken_LineNum = 0;
+            final int kToken_CardNum = 1;
+            final int kToken_DeviceNum = 2;
+            final int kToken_Type0 = 3; // "digital", "control", "raw"
+            final int kToken_Type1 = 4; // "audio", "midi"
+            final int kToken_Type2 = 5; // "capture", "playback"
+
+            int tokenOffset = 0;
+            int delimOffset = 0;
+            int tokenIndex = kToken_LineNum;
+            while (true) {
+                tokenOffset = mTokenizer.nextToken(line, delimOffset);
+                if (tokenOffset == LineTokenizer.kTokenNotFound) {
+                    break; // bail
+                }
+                delimOffset = mTokenizer.nextDelimiter(line, tokenOffset);
+                if (delimOffset == LineTokenizer.kTokenNotFound) {
+                    delimOffset = line.length();
+                }
+                String token = line.substring(tokenOffset, delimOffset);
+
+                switch (tokenIndex) {
+                case kToken_LineNum:
+                    // ignore
+                    break;
+
+                case kToken_CardNum:
+                    mCardNum = Integer.parseInt(token);
+                    if (line.charAt(delimOffset) != '-') {
+                        tokenIndex++; // no device # in the token stream
+                    }
+                    break;
+
+                case kToken_DeviceNum:
+                    mDeviceNum = Integer.parseInt(token);
+                    break;
+
+                case kToken_Type0:
+                    if (token.equals("digital")) {
+                        // NOP
+                    } else if (token.equals("control")) {
+                        mDeviceType = kDeviceType_Control;
+                    } else if (token.equals("raw")) {
+                        // NOP
+                    }
+                    break;
+
+                case kToken_Type1:
+                    if (token.equals("audio")) {
+                        mDeviceType = kDeviceType_Audio;
+                    } else if (token.equals("midi")) {
+                        mDeviceType = kDeviceType_MIDI;
+                        mHasMIDIDevices = true;
+                    }
+                    break;
+
+                case kToken_Type2:
+                    if (token.equals("capture")) {
+                        mDeviceDir = kDeviceDir_Capture;
+                        mHasCaptureDevices = true;
+                    } else if (token.equals("playback")) {
+                        mDeviceDir = kDeviceDir_Playback;
+                        mHasPlaybackDevices = true;
+                    }
+                    break;
+                } // switch (tokenIndex)
+
+                tokenIndex++;
+            } // while (true)
+
+            return true;
+        } // parse()
+
+        public String textFormat() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("[" + mCardNum + ":" + mDeviceNum + "]");
+
+            switch (mDeviceType) {
+            case kDeviceType_Unknown:
+                sb.append(" N/A");
+                break;
+            case kDeviceType_Audio:
+                sb.append(" Audio");
+                break;
+            case kDeviceType_Control:
+                sb.append(" Control");
+                break;
+            case kDeviceType_MIDI:
+                sb.append(" MIDI");
+                break;
+            }
+
+            switch (mDeviceDir) {
+            case kDeviceDir_Unknown:
+                sb.append(" N/A");
+                break;
+            case kDeviceDir_Capture:
+                sb.append(" Capture");
+                break;
+            case kDeviceDir_Playback:
+                sb.append(" Playback");
+                break;
+            }
+
+            return sb.toString();
+        }
+    }
+
+    private Vector<AlsaDeviceRecord>
+            deviceRecords_ = new Vector<AlsaDeviceRecord>();
+
+    private boolean isLineDeviceRecord(String line) {
+        return line.charAt(kIndex_CardDeviceField) == '[';
+    }
+
+    public AlsaDevicesParser() {
+    }
+
+    public int getNumDeviceRecords() {
+        return deviceRecords_.size();
+    }
+
+    public AlsaDeviceRecord getDeviceRecordAt(int index) {
+        return deviceRecords_.get(index);
+    }
+
+    public void Log() {
+        int numDevRecs = getNumDeviceRecords();
+        for (int index = 0; index < numDevRecs; ++index) {
+            Slog.w(TAG, "usb:" + getDeviceRecordAt(index).textFormat());
+        }
+    }
+
+    public boolean hasPlaybackDevices() {
+        return mHasPlaybackDevices;
+    }
+
+    public boolean hasCaptureDevices() {
+        return mHasCaptureDevices;
+    }
+
+    public boolean hasMIDIDevices() {
+        return mHasMIDIDevices;
+    }
+
+    public void scan() {
+        deviceRecords_.clear();
+
+        final String devicesFilePath = "/proc/asound/devices";
+        File devicesFile = new File(devicesFilePath);
+        try {
+            FileReader reader = new FileReader(devicesFile);
+            BufferedReader bufferedReader = new BufferedReader(reader);
+            String line = "";
+            while ((line = bufferedReader.readLine()) != null) {
+                if (isLineDeviceRecord(line)) {
+                    AlsaDeviceRecord deviceRecord = new AlsaDeviceRecord();
+                    deviceRecord.parse(line);
+                    deviceRecords_.add(deviceRecord);
+                }
+            }
+            reader.close();
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+} // class AlsaDevicesParser
+
diff --git a/core/java/android/alsa/LineTokenizer.java b/core/java/android/alsa/LineTokenizer.java
new file mode 100644
index 0000000..c138fc5
--- /dev/null
+++ b/core/java/android/alsa/LineTokenizer.java
@@ -0,0 +1,57 @@
+/*
+ * 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.alsascan;
+
+/**
+ * @hide
+ * Breaks lines in an ALSA "cards" or "devices" file into tokens.
+ * TODO(pmclean) Look into replacing this with String.split().
+ */
+public class LineTokenizer {
+    public static final int kTokenNotFound = -1;
+
+    private String mDelimiters = "";
+
+    public LineTokenizer(String delimiters) {
+        mDelimiters = delimiters;
+    }
+
+    int nextToken(String line, int startIndex) {
+        int len = line.length();
+        int offset = startIndex;
+        for (; offset < len; offset++) {
+            if (mDelimiters.indexOf(line.charAt(offset)) == -1) {
+                // past a delimiter
+                break;
+            }
+      }
+
+      return offset < len ? offset : kTokenNotFound;
+    }
+
+    int nextDelimiter(String line, int startIndex) {
+        int len = line.length();
+        int offset = startIndex;
+        for (; offset < len; offset++) {
+            if (mDelimiters.indexOf(line.charAt(offset)) != -1) {
+                // past a delimiter
+                break;
+            }
+        }
+
+      return offset < len ? offset : kTokenNotFound;
+    }
+}
diff --git a/core/java/android/animation/RevealAnimator.java b/core/java/android/animation/RevealAnimator.java
new file mode 100644
index 0000000..77a536a
--- /dev/null
+++ b/core/java/android/animation/RevealAnimator.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.animation;
+
+import android.view.View;
+
+import java.util.ArrayList;
+
+/**
+ * Reveals a View with an animated clipping circle.
+ * The clipping is implemented efficiently by talking to a private reveal API on View.
+ * This hidden class currently only accessed by the {@link android.view.View}.
+ *
+ * @hide
+ */
+public class RevealAnimator extends ValueAnimator {
+    private final static String LOGTAG = "RevealAnimator";
+    private ValueAnimator.AnimatorListener mListener;
+    private ValueAnimator.AnimatorUpdateListener mUpdateListener;
+    private RevealCircle mReuseRevealCircle = new RevealCircle(0);
+    private RevealAnimator(final View clipView, final int x, final int y,
+            float startRadius, float endRadius, final boolean inverseClip) {
+
+        setObjectValues(new RevealCircle(startRadius), new RevealCircle(endRadius));
+        setEvaluator(new RevealCircleEvaluator(mReuseRevealCircle));
+
+        mUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
+                @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                RevealCircle circle = (RevealCircle) animation.getAnimatedValue();
+                float radius = circle.getRadius();
+                clipView.setRevealClip(true, inverseClip, x, y, radius);
+            }
+        };
+        mListener = new AnimatorListenerAdapter() {
+                @Override
+            public void onAnimationCancel(Animator animation) {
+                clipView.setRevealClip(false, false, 0, 0, 0);
+            }
+
+                @Override
+            public void onAnimationEnd(Animator animation) {
+                clipView.setRevealClip(false, false, 0, 0, 0);
+            }
+        };
+        addUpdateListener(mUpdateListener);
+        addListener(mListener);
+    }
+
+    public static RevealAnimator ofRevealCircle(View clipView, int x, int y,
+            float startRadius, float endRadius, boolean inverseClip) {
+        RevealAnimator anim = new RevealAnimator(clipView, x, y,
+                startRadius, endRadius, inverseClip);
+        return anim;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void removeAllUpdateListeners() {
+        super.removeAllUpdateListeners();
+        addUpdateListener(mUpdateListener);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void removeAllListeners() {
+        super.removeAllListeners();
+        addListener(mListener);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ArrayList<AnimatorListener> getListeners() {
+        ArrayList<AnimatorListener> allListeners =
+                (ArrayList<AnimatorListener>) super.getListeners().clone();
+        allListeners.remove(mListener);
+        return allListeners;
+    }
+
+    private class RevealCircle {
+        float mRadius;
+
+        public RevealCircle(float radius) {
+            mRadius = radius;
+        }
+
+        public void setRadius(float radius) {
+            mRadius = radius;
+        }
+
+        public float getRadius() {
+            return mRadius;
+        }
+    }
+
+    private class RevealCircleEvaluator implements TypeEvaluator<RevealCircle> {
+
+        private RevealCircle mRevealCircle;
+
+        public RevealCircleEvaluator() {
+        }
+
+        public RevealCircleEvaluator(RevealCircle reuseCircle) {
+            mRevealCircle = reuseCircle;
+        }
+
+        @Override
+        public RevealCircle evaluate(float fraction, RevealCircle startValue,
+                RevealCircle endValue) {
+            float currentRadius = startValue.mRadius
+                    + ((endValue.mRadius - startValue.mRadius) * fraction);
+            if (mRevealCircle == null) {
+                return new RevealCircle(currentRadius);
+            } else {
+                mRevealCircle.setRadius(currentRadius);
+                return mRevealCircle;
+            }
+        }
+    }
+}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d386eff..9d6a340 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -605,11 +605,11 @@
     public static final int RECENT_IGNORE_UNAVAILABLE = 0x0002;
 
     /**
-     * Provides a list that also contains recent tasks for user
-     * and related users.
+     * Provides a list that contains recent tasks for all
+     * profiles of a user.
      * @hide
      */
-    public static final int RECENT_INCLUDE_RELATED = 0x0004;
+    public static final int RECENT_INCLUDE_PROFILES = 0x0004;
 
     /**
      * Return a list of the tasks that the user has recently launched, with
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 0615bd9..6ca5244 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -29,6 +29,7 @@
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.IPackageInstallObserver;
+import android.content.pm.IPackageInstallObserver2;
 import android.content.pm.IPackageManager;
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
@@ -1073,7 +1074,7 @@
     public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
                                String installerPackageName) {
         try {
-            mPM.installPackage(packageURI, observer, flags, installerPackageName);
+            mPM.installPackageEtc(packageURI, observer, null, flags, installerPackageName);
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -1084,8 +1085,8 @@
             int flags, String installerPackageName, Uri verificationURI,
             ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
         try {
-            mPM.installPackageWithVerification(packageURI, observer, flags, installerPackageName,
-                    verificationURI, manifestDigest, encryptionParams);
+            mPM.installPackageWithVerificationEtc(packageURI, observer, null, flags,
+                    installerPackageName, verificationURI, manifestDigest, encryptionParams);
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -1096,8 +1097,46 @@
             IPackageInstallObserver observer, int flags, String installerPackageName,
             VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
         try {
-            mPM.installPackageWithVerificationAndEncryption(packageURI, observer, flags,
-                    installerPackageName, verificationParams, encryptionParams);
+            mPM.installPackageWithVerificationAndEncryptionEtc(packageURI, observer, null,
+                    flags, installerPackageName, verificationParams, encryptionParams);
+        } catch (RemoteException e) {
+            // Should never happen!
+        }
+    }
+
+    // Expanded observer-API versions
+    @Override
+    public void installPackage(Uri packageURI, PackageInstallObserver observer,
+            int flags, String installerPackageName) {
+        try {
+            mPM.installPackageEtc(packageURI, null, observer.mObserver,
+                    flags, installerPackageName);
+        } catch (RemoteException e) {
+            // Should never happen!
+        }
+    }
+
+    @Override
+    public void installPackageWithVerification(Uri packageURI,
+            PackageInstallObserver observer, int flags, String installerPackageName,
+            Uri verificationURI, ManifestDigest manifestDigest,
+            ContainerEncryptionParams encryptionParams) {
+        try {
+            mPM.installPackageWithVerificationEtc(packageURI, null, observer.mObserver, flags,
+                    installerPackageName, verificationURI, manifestDigest, encryptionParams);
+        } catch (RemoteException e) {
+            // Should never happen!
+        }
+    }
+
+    @Override
+    public void installPackageWithVerificationAndEncryption(Uri packageURI,
+            PackageInstallObserver observer, int flags, String installerPackageName,
+            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
+        try {
+            mPM.installPackageWithVerificationAndEncryptionEtc(packageURI, null,
+                    observer.mObserver, flags, installerPackageName, verificationParams,
+                    encryptionParams);
         } catch (RemoteException e) {
             // Should never happen!
         }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 589c82f..d1f94f0 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -75,6 +75,8 @@
 import android.net.nsd.NsdManager;
 import android.net.wifi.IWifiManager;
 import android.net.wifi.WifiManager;
+import android.net.wifi.hotspot.IWifiHotspotManager;
+import android.net.wifi.hotspot.WifiHotspotManager;
 import android.net.wifi.p2p.IWifiP2pManager;
 import android.net.wifi.p2p.WifiP2pManager;
 import android.nfc.NfcManager;
@@ -117,6 +119,7 @@
 import android.accounts.AccountManager;
 import android.accounts.IAccountManager;
 import android.app.admin.DevicePolicyManager;
+import android.app.trust.TrustManager;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsService;
@@ -552,6 +555,13 @@
                     return new WifiManager(ctx.getOuterContext(), service);
                 }});
 
+        registerService(WIFI_HOTSPOT_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    IBinder b = ServiceManager.getService(WIFI_HOTSPOT_SERVICE);
+                    IWifiHotspotManager service = IWifiHotspotManager.Stub.asInterface(b);
+                    return new WifiHotspotManager(ctx.getOuterContext(), service);
+                }});
+
         registerService(WIFI_P2P_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
                     IBinder b = ServiceManager.getService(WIFI_P2P_SERVICE);
@@ -612,6 +622,12 @@
                 return new MediaSessionManager(ctx);
             }
         });
+        registerService(TRUST_SERVICE, new ServiceFetcher() {
+            public Object createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(TRUST_SERVICE);
+                return new TrustManager(b);
+            }
+        });
     }
 
     static ContextImpl getImpl(Context context) {
diff --git a/core/java/android/app/IBackupAgent.aidl b/core/java/android/app/IBackupAgent.aidl
index 4ca06ed..7036aea 100644
--- a/core/java/android/app/IBackupAgent.aidl
+++ b/core/java/android/app/IBackupAgent.aidl
@@ -124,4 +124,12 @@
             int type, String domain, String path, long mode, long mtime,
             int token, IBackupManager callbackBinder);
 
+    /**
+     * Out of band: instruct the agent to crash within the client process.  This is used
+     * when the backup infrastructure detects a semantic error post-hoc and needs to
+     * pass the problem back to the app.
+     *
+     * @param message The message to be passed to the agent's application in an exception.
+     */
+    void fail(String message);
 }
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 9f933ca..9911467 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -45,7 +45,8 @@
     void unregisterListener(in INotificationListener listener, int userid);
 
     void cancelNotificationFromListener(in INotificationListener token, String pkg, String tag, int id);
-    void cancelAllNotificationsFromListener(in INotificationListener token);
+    void cancelNotificationsFromListener(in INotificationListener token, in String[] keys);
 
-    StatusBarNotification[] getActiveNotificationsFromListener(in INotificationListener token);
+    StatusBarNotification[] getActiveNotificationsFromListener(in INotificationListener token, in String[] keys);
+    String[] getActiveNotificationKeysFromListener(in INotificationListener token);
 }
\ No newline at end of file
diff --git a/core/java/android/app/PackageInstallObserver.java b/core/java/android/app/PackageInstallObserver.java
new file mode 100644
index 0000000..dacffb4
--- /dev/null
+++ b/core/java/android/app/PackageInstallObserver.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.content.pm.IPackageInstallObserver2;
+import android.os.Bundle;
+import android.os.RemoteException;
+
+/**
+ * @hide
+ *
+ * New-style observer for package installers to use.
+ */
+public class PackageInstallObserver {
+    IPackageInstallObserver2.Stub mObserver = new IPackageInstallObserver2.Stub() {
+        @Override
+        public void packageInstalled(String pkgName, Bundle extras, int result)
+                throws RemoteException {
+            PackageInstallObserver.this.packageInstalled(pkgName, extras, result);
+        }
+    };
+
+    /**
+     * This method will be called to report the result of the package installation attempt.
+     *
+     * @param pkgName Name of the package whose installation was attempted
+     * @param extras If non-null, this Bundle contains extras providing additional information
+     *        about an install failure.  See {@link android.content.pm.PackageManager} for
+     *        documentation about which extras apply to various failures; in particular the
+     *        strings named EXTRA_FAILURE_*.
+     * @param result The numeric success or failure code indicating the basic outcome
+     */
+    public void packageInstalled(String pkgName, Bundle extras, int result) {
+    }
+}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 8efc14f..cf14202 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -121,8 +121,8 @@
      */
     public static final int FLAG_ONE_SHOT = 1<<30;
     /**
-     * Flag indicating that if the described PendingIntent already
-     * exists, then simply return null instead of creating it.
+     * Flag indicating that if the described PendingIntent does not
+     * already exist, then simply return null instead of creating it.
      * For use with {@link #getActivity}, {@link #getBroadcast}, and
      * {@link #getService}.
      */
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 66fc816..3074b49 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -52,6 +52,22 @@
     static final String TAG = "DeviceAdminInfo";
 
     /**
+     * A type of policy that this device admin can use: device owner meta-policy
+     * for an admin that is designated as owner of the device.
+     *
+     * @hide
+     */
+    public static final int USES_POLICY_DEVICE_OWNER = -2;
+
+    /**
+     * A type of policy that this device admin can use: profile owner meta-policy
+     * for admins that have been installed as owner of some user profile.
+     *
+     * @hide
+     */
+    public static final int USES_POLICY_PROFILE_OWNER = -1;
+
+    /**
      * A type of policy that this device admin can use: limit the passwords
      * that the user can select, via {@link DevicePolicyManager#setPasswordQuality}
      * and {@link DevicePolicyManager#setPasswordMinimumLength}.
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 67c772b..3c31f8d 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -128,6 +128,13 @@
 
     Handler mHandler = null;
 
+    Handler getHandler() {
+        if (mHandler == null) {
+            mHandler = new Handler(Looper.getMainLooper());
+        }
+        return mHandler;
+    }
+
     class SharedPrefsSynchronizer implements Runnable {
         public final CountDownLatch mLatch = new CountDownLatch(1);
 
@@ -140,12 +147,9 @@
 
     // Syncing shared preferences deferred writes needs to happen on the main looper thread
     private void waitForSharedPrefs() {
-        if (mHandler == null) {
-            mHandler = new Handler(Looper.getMainLooper());
-        }
-
+        Handler h = getHandler();
         final SharedPrefsSynchronizer s = new SharedPrefsSynchronizer();
-        mHandler.postAtFrontOfQueue(s);
+        h.postAtFrontOfQueue(s);
         try {
             s.mLatch.await();
         } catch (InterruptedException e) { /* ignored */ }
@@ -680,5 +684,23 @@
                 }
             }
         }
+
+        @Override
+        public void fail(String message) {
+            getHandler().post(new FailRunnable(message));
+        }
+    }
+
+    static class FailRunnable implements Runnable {
+        private String mMessage;
+
+        FailRunnable(String message) {
+            mMessage = message;
+        }
+
+        @Override
+        public void run() {
+            throw new IllegalStateException(mMessage);
+        }
     }
 }
diff --git a/core/java/android/app/backup/BackupDataOutput.java b/core/java/android/app/backup/BackupDataOutput.java
index 845784f..fc5fb3d 100644
--- a/core/java/android/app/backup/BackupDataOutput.java
+++ b/core/java/android/app/backup/BackupDataOutput.java
@@ -85,11 +85,6 @@
      * @throws IOException if the write failed
      */
     public int writeEntityHeader(String key, int dataSize) throws IOException {
-        if (key != null && key.charAt(0) >= 0xff00) {
-            if (Process.myUid() != Process.SYSTEM_UID) {
-                throw new IllegalArgumentException("Invalid key " + key);
-            }
-        }
         int result = writeEntityHeader_native(mBackupWriter, key, dataSize);
         if (result >= 0) {
             return result;
diff --git a/core/java/android/app/trust/ITrustListener.aidl b/core/java/android/app/trust/ITrustListener.aidl
new file mode 100644
index 0000000..4680043
--- /dev/null
+++ b/core/java/android/app/trust/ITrustListener.aidl
@@ -0,0 +1,26 @@
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+package android.app.trust;
+
+/**
+ * Private API to be notified about trust changes.
+ *
+ * {@hide}
+ */
+oneway interface ITrustListener {
+    void onTrustChanged(boolean enabled, int userId);
+}
\ No newline at end of file
diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
new file mode 100644
index 0000000..ad4ccbb
--- /dev/null
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -0,0 +1,31 @@
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+package android.app.trust;
+
+import android.app.trust.ITrustListener;
+
+/**
+ * System private API to comunicate with trust service.
+ *
+ * {@hide}
+ */
+interface ITrustManager {
+    void reportUnlockAttempt(boolean successful, int userId);
+    void reportEnabledTrustAgentsChanged(int userId);
+    void registerTrustListener(in ITrustListener trustListener);
+    void unregisterTrustListener(in ITrustListener trustListener);
+}
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
new file mode 100644
index 0000000..e31c624
--- /dev/null
+++ b/core/java/android/app/trust/TrustManager.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.app.trust;
+
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+
+/**
+ * See {@link com.android.server.trust.TrustManagerService}
+ * @hide
+ */
+public class TrustManager {
+
+    private static final int MSG_TRUST_CHANGED = 1;
+
+    private static final String TAG = "TrustManager";
+
+    private final ITrustManager mService;
+    private final ArrayMap<TrustListener, ITrustListener> mTrustListeners;
+
+    public TrustManager(IBinder b) {
+        mService = ITrustManager.Stub.asInterface(b);
+        mTrustListeners = new ArrayMap<TrustListener, ITrustListener>();
+    }
+
+    /**
+     * Reports that user {@param userId} has tried to unlock the device.
+     *
+     * @param successful if true, the unlock attempt was successful.
+     *
+     * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
+     */
+    public void reportUnlockAttempt(boolean successful, int userId) {
+        try {
+            mService.reportUnlockAttempt(successful, userId);
+        } catch (RemoteException e) {
+            onError(e);
+        }
+    }
+
+    /**
+     * Reports that the list of enabled trust agents changed for user {@param userId}.
+     *
+     * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
+     */
+    public void reportEnabledTrustAgentsChanged(int userId) {
+        try {
+            mService.reportEnabledTrustAgentsChanged(userId);
+        } catch (RemoteException e) {
+            onError(e);
+        }
+    }
+
+    /**
+     * Registers a listener for trust events.
+     *
+     * Requires the {@link android.Manifest.permission#TRUST_LISTENER} permission.
+     */
+    public void registerTrustListener(final TrustListener trustListener) {
+        try {
+            ITrustListener.Stub iTrustListener = new ITrustListener.Stub() {
+                @Override
+                public void onTrustChanged(boolean enabled, int userId) throws RemoteException {
+                    mHandler.obtainMessage(MSG_TRUST_CHANGED, (enabled ? 1 : 0), userId,
+                            trustListener).sendToTarget();
+                }
+            };
+            mService.registerTrustListener(iTrustListener);
+            mTrustListeners.put(trustListener, iTrustListener);
+        } catch (RemoteException e) {
+            onError(e);
+        }
+    }
+
+    /**
+     * Unregisters a listener for trust events.
+     *
+     * Requires the {@link android.Manifest.permission#TRUST_LISTENER} permission.
+     */
+    public void unregisterTrustListener(final TrustListener trustListener) {
+        ITrustListener iTrustListener = mTrustListeners.remove(trustListener);
+        if (iTrustListener != null) {
+            try {
+                mService.unregisterTrustListener(iTrustListener);
+            } catch (RemoteException e) {
+                onError(e);
+            }
+        }
+    }
+
+    private void onError(Exception e) {
+        Log.e(TAG, "Error while calling TrustManagerService", e);
+    }
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+        @Override
+        public void handleMessage(Message msg) {
+            switch(msg.what) {
+                case MSG_TRUST_CHANGED:
+                    ((TrustListener)msg.obj).onTrustChanged(msg.arg1 != 0, msg.arg2);
+                    break;
+            }
+        }
+    };
+
+    public interface TrustListener {
+
+        /**
+         * Reports that the trust state has changed.
+         * @param enabled if true, the system believes the environment to be trusted.
+         * @param userId the user, for which the trust changed.
+         */
+        void onTrustChanged(boolean enabled, int userId);
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index a4374b8..e79deec 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -567,7 +567,7 @@
     }
 
     /**
-     * Stop BLE advertising.
+     * Stop BLE advertising. The callback has to be the same one used for start advertising.
      *
      * @param callback - {@link AdvertiseCallback}
      * @return true if BLE advertising stops, false otherwise.
@@ -1986,7 +1986,13 @@
         public void onAdvertiseStateChange(int advertiseState, int status) {
             Log.d(TAG, "on advertise call back, state: " + advertiseState + " status: " + status);
             if (advertiseState == STATE_ADVERTISE_STARTED) {
-                mAdvertiseCallback.onAdvertiseStart(status);
+                if (status == ADVERTISE_CALLBACK_SUCCESS) {
+                    mAdvertiseCallback.onAdvertiseStart(status);
+                } else {
+                    // If status is unsuccessful and advertise state is started, it means stop
+                    // advertising fails.
+                    mAdvertiseCallback.onAdvertiseStop(status);
+                }
             } else {
                 synchronized (this) {
                     if (status == ADVERTISE_CALLBACK_SUCCESS) {
@@ -2008,8 +2014,22 @@
                         }
                     }
                 }
-                mAdvertiseCallback.onAdvertiseStop(status);
+                if (status == ADVERTISE_CALLBACK_SUCCESS) {
+                    mAdvertiseCallback.onAdvertiseStop(status);
+                } else{
+                    // If status is unsuccesful and advertise state is stopped, it means start
+                    // advertising fails.
+                    mAdvertiseCallback.onAdvertiseStart(status);
+                }
             }
         }
+
+        /**
+         * Callback reporting LE ATT MTU.
+         * @hide
+         */
+        public void onConfigureMTU(String address, int mtu, int status) {
+            // no op
+        }
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 39305b0..101b721 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -550,6 +550,23 @@
             public void onAdvertiseStateChange(int state, int status) {
                 if (DBG) Log.d(TAG, "onAdvertiseStateChange() - state = "
                         + state + " status=" + status);
+	    }
+
+            /**
+             * Callback invoked when the MTU for a given connection changes
+             * @hide
+             */
+            public void onConfigureMTU(String address, int mtu, int status) {
+                if (DBG) Log.d(TAG, "onConfigureMTU() - Device=" + address +
+                            " mtu=" + mtu + " status=" + status);
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                try {
+                    mCallback.onConfigureMTU(BluetoothGatt.this, mtu, status);
+                } catch (Exception ex) {
+                    Log.w(TAG, "Unhandled exception in callback", ex);
+                }
             }
         };
 
@@ -1137,6 +1154,36 @@
     }
 
     /**
+     * Configure the MTU used for a given connection.
+     *
+     * <p>When performing a write request operation (write without response),
+     * the data sent is truncated to the MTU size. This function may be used
+     * to request a larget MTU size to be able to send more data at once.
+     *
+     * <p>A {@link BluetoothGattCallback#onConfigureMTU} callback will indicate
+     * whether this operation was successful.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @return true, if the new MTU value has been requested successfully
+     * @hide
+     */
+    public boolean configureMTU(int mtu) {
+        if (DBG) Log.d(TAG, "configureMTU() - device: " + mDevice.getAddress()
+                            + " mtu: " + mtu);
+        if (mService == null || mClientIf == 0) return false;
+
+        try {
+            mService.configureMTU(mClientIf, mDevice.getAddress(), mtu);
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
      * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
      * with {@link BluetoothProfile#GATT} as argument
      *
diff --git a/core/java/android/bluetooth/BluetoothGattCallback.java b/core/java/android/bluetooth/BluetoothGattCallback.java
index 80ea4a6..5180259 100644
--- a/core/java/android/bluetooth/BluetoothGattCallback.java
+++ b/core/java/android/bluetooth/BluetoothGattCallback.java
@@ -138,4 +138,19 @@
      */
     public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
     }
+
+    /**
+     * Callback indicating the MTU for a given device connection has changed.
+     *
+     * This callback is triggered in response to the
+     * {@link BluetoothGatt#configureMTU} function, or in response to a connection
+     * event.
+     *
+     * @param gatt GATT client invoked {@link BluetoothGatt#configureMTU}
+     * @param mtu The new MTU size
+     * @param status {@link BluetoothGatt#GATT_SUCCESS} if the MTU has been changed successfully
+     * @hide
+     */
+    public void onConfigureMTU(BluetoothGatt gatt, int mtu, int status) {
+    }
 }
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 784cdcc..c6b5c3d 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -73,6 +73,7 @@
     void beginReliableWrite(in int clientIf, in String address);
     void endReliableWrite(in int clientIf, in String address, in boolean execute);
     void readRemoteRssi(in int clientIf, in String address);
+    void configureMTU(in int clientIf, in String address, in int mtu);
 
     void registerServer(in ParcelUuid appId, in IBluetoothGattServerCallback callback);
     void unregisterServer(in int serverIf);
diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
index 7c69a06..a78c29b 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -64,4 +64,5 @@
                              in byte[] value);
     void onReadRemoteRssi(in String address, in int rssi, in int status);
     oneway void onAdvertiseStateChange(in int advertiseState, in int status);
+    void onConfigureMTU(in String address, in int mtu, in int status);
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 9f0c384..3fdaef2 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1974,6 +1974,7 @@
             //@hide: NETWORK_STATS_SERVICE,
             //@hide: NETWORK_POLICY_SERVICE,
             WIFI_SERVICE,
+            WIFI_HOTSPOT_SERVICE,
             WIFI_P2P_SERVICE,
             NSD_SERVICE,
             AUDIO_SERVICE,
@@ -2324,6 +2325,16 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
+     * android.net.wifi.hotspot.WifiHotspotManager} for handling management of
+     * Wi-Fi hotspot access.
+     *
+     * @see #getSystemService
+     * @see android.net.wifi.hotspot.WifiHotspotManager
+     */
+    public static final String WIFI_HOTSPOT_SERVICE = "wifihotspot";
+
+    /**
+     * Use with {@link #getSystemService} to retrieve a {@link
      * android.net.wifi.p2p.WifiP2pManager} for handling management of
      * Wi-Fi peer-to-peer connections.
      *
@@ -2584,6 +2595,14 @@
     public static final String CONSUMER_IR_SERVICE = "consumer_ir";
 
     /**
+     * {@link android.app.trust.TrustManager} for managing trust agents.
+     * @see #getSystemService
+     * @see android.app.trust.TrustManager
+     * @hide
+     */
+    public static final String TRUST_SERVICE = "trust";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 102433b..d189a34 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2884,6 +2884,14 @@
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_CAR_MODE = "android.intent.category.CAR_MODE";
 
+    /**
+     * An activity that provides a user interface for adjusting notification preferences for its
+     * containing application. Optional but recommended for apps that post
+     * {@link android.app.Notification Notifications}.
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Application launch intent categories (see addCategory()).
diff --git a/core/java/android/content/pm/IPackageInstallObserver2.aidl b/core/java/android/content/pm/IPackageInstallObserver2.aidl
new file mode 100644
index 0000000..2602ab5
--- /dev/null
+++ b/core/java/android/content/pm/IPackageInstallObserver2.aidl
@@ -0,0 +1,45 @@
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.content.pm;
+
+import android.os.Bundle;
+
+/**
+ * API for installation callbacks from the Package Manager.  In certain result cases
+ * additional information will be provided.
+ * @hide
+ */
+oneway interface IPackageInstallObserver2 {
+    /**
+     * The install operation has completed.  {@code returnCode} holds a numeric code
+     * indicating success or failure.  In certain cases the {@code extras} Bundle will
+     * contain additional details:
+     *
+     * <p><table>
+     * <tr>
+     *   <td>INSTALL_FAILED_DUPLICATE_PERMISSION</td>
+     *   <td>Two strings are provided in the extras bundle: EXTRA_EXISTING_PERMISSION
+     *       is the name of the permission that the app is attempting to define, and
+     *       EXTRA_EXISTING_PACKAGE is the package name of the app which has already
+     *       defined the permission.</td>
+     * </tr>
+     * </table>
+     */
+    void packageInstalled(in String packageName, in Bundle extras, int returnCode);
+}
+
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index c9fb530..ae0899f 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -25,6 +25,7 @@
 import android.content.pm.ContainerEncryptionParams;
 import android.content.pm.FeatureInfo;
 import android.content.pm.IPackageInstallObserver;
+import android.content.pm.IPackageInstallObserver2;
 import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageMoveObserver;
@@ -406,6 +407,21 @@
             in VerificationParams verificationParams,
             in ContainerEncryptionParams encryptionParams);
 
+    /** Expanded observer versions */
+    void installPackageEtc(in Uri packageURI, IPackageInstallObserver observer,
+            IPackageInstallObserver2 observer2, int flags, in String installerPackageName);
+
+    void installPackageWithVerificationEtc(in Uri packageURI,
+            in IPackageInstallObserver observer, IPackageInstallObserver2 observer2,
+            int flags, in String installerPackageName, in Uri verificationURI,
+            in ManifestDigest manifestDigest, in ContainerEncryptionParams encryptionParams);
+
+    void installPackageWithVerificationAndEncryptionEtc(in Uri packageURI,
+            in IPackageInstallObserver observer, in IPackageInstallObserver2 observer2,
+            int flags, in String installerPackageName,
+            in VerificationParams verificationParams,
+            in ContainerEncryptionParams encryptionParams);
+
     int installExistingPackageAsUser(String packageName, int userId);
 
     void verifyPendingInstall(int id, int verificationCode);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e86833b..ceb7764 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.app.PackageInstallObserver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -683,6 +684,20 @@
     public static final int INSTALL_FAILED_USER_RESTRICTED = -111;
 
     /**
+     * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+     * if the system failed to install the package because it is attempting to define a
+     * permission that is already defined by some existing package.
+     *
+     * <p>The package name of the app which has already defined the permission is passed to
+     * a {@link IPackageInstallObserver2}, if any, as the {@link #EXTRA_EXISTING_PACKAGE}
+     * string extra; and the name of the permission being redefined is passed in the
+     * {@link #EXTRA_EXISTING_PERMISSION} string extra.
+     * @hide
+     */
+    public static final int INSTALL_FAILED_DUPLICATE_PERMISSION = -112;
+
+    /**
      * Flag parameter for {@link #deletePackage} to indicate that you don't want to delete the
      * package's data directory.
      *
@@ -1390,6 +1405,24 @@
             = "android.content.pm.extra.PERMISSION_LIST";
 
     /**
+     * String extra for {@link IPackageInstallObserver2} in the 'extras' Bundle in case of
+     * {@link #INSTALL_FAILED_DUPLICATE_PERMISSION}.  This extra names the package which provides
+     * the existing definition for the permission.
+     * @hide
+     */
+    public static final String EXTRA_FAILURE_EXISTING_PACKAGE
+            = "android.content.pm.extra.FAILURE_EXISTING_PACKAGE";
+
+    /**
+     * String extra for {@link IPackageInstallObserver2} in the 'extras' Bundle in case of
+     * {@link #INSTALL_FAILED_DUPLICATE_PERMISSION}.  This extra names the permission that is
+     * being redundantly defined by the package being installed.
+     * @hide
+     */
+    public static final String EXTRA_FAILURE_EXISTING_PERMISSION
+            = "android.content.pm.extra.FAILURE_EXISTING_PERMISSION";
+
+    /**
      * Retrieve overall information about an application package that is
      * installed on the system.
      * <p>
@@ -2752,11 +2785,14 @@
      * 'content:' URI.
      * @param observer An observer callback to get notified when the package installation is
      * complete. {@link IPackageInstallObserver#packageInstalled(String, int)} will be
-     * called when that happens.  observer may be null to indicate that no callback is desired.
+     * called when that happens.  This parameter must not be null.
      * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
      * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
      * @param installerPackageName Optional package name of the application that is performing the
      * installation. This identifies which market the package came from.
+     * @deprecated Use {@link #installPackage(Uri, IPackageInstallObserver2, int, String)}
+     * instead.  This method will continue to be supported but the older observer interface
+     * will not get additional failure details.
      */
     public abstract void installPackage(
             Uri packageURI, IPackageInstallObserver observer, int flags,
@@ -2772,11 +2808,9 @@
      * @param observer An observer callback to get notified when the package
      *            installation is complete.
      *            {@link IPackageInstallObserver#packageInstalled(String, int)}
-     *            will be called when that happens. observer may be null to
-     *            indicate that no callback is desired.
+     *            will be called when that happens. This parameter must not be null.
      * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
-     *            {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}
-     *            .
+     *            {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
      * @param installerPackageName Optional package name of the application that
      *            is performing the installation. This identifies which market
      *            the package came from.
@@ -2789,6 +2823,10 @@
      *            these parameters describing the encryption and authentication
      *            used. May be {@code null}.
      * @hide
+     * @deprecated Use {@link #installPackageWithVerification(Uri, IPackageInstallObserver2,
+     * int, String, Uri, ManifestDigest, ContainerEncryptionParams)} instead.  This method will
+     * continue to be supported but the older observer interface will not get additional failure
+     * details.
      */
     public abstract void installPackageWithVerification(Uri packageURI,
             IPackageInstallObserver observer, int flags, String installerPackageName,
@@ -2805,11 +2843,99 @@
      * @param observer An observer callback to get notified when the package
      *            installation is complete.
      *            {@link IPackageInstallObserver#packageInstalled(String, int)}
-     *            will be called when that happens. observer may be null to
-     *            indicate that no callback is desired.
+     *            will be called when that happens. This parameter must not be null.
      * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
-     *            {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}
-     *            .
+     *            {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
+     * @param installerPackageName Optional package name of the application that
+     *            is performing the installation. This identifies which market
+     *            the package came from.
+     * @param verificationParams an object that holds signal information to
+     *            assist verification. May be {@code null}.
+     * @param encryptionParams if the package to be installed is encrypted,
+     *            these parameters describing the encryption and authentication
+     *            used. May be {@code null}.
+     *
+     * @hide
+     * @deprecated Use {@link #installPackageWithVerificationAndEncryption(Uri,
+     * IPackageInstallObserver2, int, String, VerificationParams,
+     * ContainerEncryptionParams)} instead.  This method will continue to be
+     * supported but the older observer interface will not get additional failure details.
+     */
+    @Deprecated
+    public abstract void installPackageWithVerificationAndEncryption(Uri packageURI,
+            IPackageInstallObserver observer, int flags, String installerPackageName,
+            VerificationParams verificationParams,
+            ContainerEncryptionParams encryptionParams);
+
+    // Package-install variants that take the new, expanded form of observer interface.
+    // Note that these *also* take the original observer type and will redundantly
+    // report the same information to that observer if supplied; but it is not required.
+
+    /**
+     * @hide
+     *
+     * Install a package. Since this may take a little while, the result will
+     * be posted back to the given observer.  An installation will fail if the calling context
+     * lacks the {@link android.Manifest.permission#INSTALL_PACKAGES} permission, if the
+     * package named in the package file's manifest is already installed, or if there's no space
+     * available on the device.
+     *
+     * @param packageURI The location of the package file to install.  This can be a 'file:' or a
+     * 'content:' URI.
+     * @param observer An observer callback to get notified when the package installation is
+     * complete. {@link PackageInstallObserver#packageInstalled(String, Bundle, int)} will be
+     * called when that happens. This parameter must not be null.
+     * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
+     * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
+     * @param installerPackageName Optional package name of the application that is performing the
+     * installation. This identifies which market the package came from.
+     */
+    public abstract void installPackage(
+            Uri packageURI, PackageInstallObserver observer,
+            int flags, String installerPackageName);
+
+    /**
+     * Similar to
+     * {@link #installPackage(Uri, IPackageInstallObserver, int, String)} but
+     * with an extra verification file provided.
+     *
+     * @param packageURI The location of the package file to install. This can
+     *            be a 'file:' or a 'content:' URI.
+     * @param observer An observer callback to get notified when the package installation is
+     * complete. {@link PackageInstallObserver#packageInstalled(String, Bundle, int)} will be
+     * called when that happens. This parameter must not be null.
+     * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
+     *            {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
+     * @param installerPackageName Optional package name of the application that
+     *            is performing the installation. This identifies which market
+     *            the package came from.
+     * @param verificationURI The location of the supplementary verification
+     *            file. This can be a 'file:' or a 'content:' URI. May be
+     *            {@code null}.
+     * @param manifestDigest an object that holds the digest of the package
+     *            which can be used to verify ownership. May be {@code null}.
+     * @param encryptionParams if the package to be installed is encrypted,
+     *            these parameters describing the encryption and authentication
+     *            used. May be {@code null}.
+     * @hide
+     */
+    public abstract void installPackageWithVerification(Uri packageURI,
+            PackageInstallObserver observer, int flags, String installerPackageName,
+            Uri verificationURI, ManifestDigest manifestDigest,
+            ContainerEncryptionParams encryptionParams);
+
+    /**
+     * Similar to
+     * {@link #installPackage(Uri, IPackageInstallObserver, int, String)} but
+     * with an extra verification information provided.
+     *
+     * @param packageURI The location of the package file to install. This can
+     *            be a 'file:' or a 'content:' URI.
+     * @param observer An observer callback to get notified when the package installation is
+     * complete. {@link PackageInstallObserver#packageInstalled(String, Bundle, int)} will be
+     * called when that happens. This parameter must not be null.
+     * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
+     *            {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
      * @param installerPackageName Optional package name of the application that
      *            is performing the installation. This identifies which market
      *            the package came from.
@@ -2822,9 +2948,8 @@
      * @hide
      */
     public abstract void installPackageWithVerificationAndEncryption(Uri packageURI,
-            IPackageInstallObserver observer, int flags, String installerPackageName,
-            VerificationParams verificationParams,
-            ContainerEncryptionParams encryptionParams);
+            PackageInstallObserver observer, int flags, String installerPackageName,
+            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams);
 
     /**
      * If there is already an application with the given package name installed
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index cf44ad8..a89c507 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1010,13 +1010,14 @@
             pkg.mSharedUserLabel = sa.getResourceId(
                     com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
         }
-        sa.recycle();
 
         pkg.installLocation = sa.getInteger(
                 com.android.internal.R.styleable.AndroidManifest_installLocation,
                 PARSE_DEFAULT_INSTALL_LOCATION);
         pkg.applicationInfo.installLocation = pkg.installLocation;
 
+        sa.recycle();
+
         /* Set the global "forward lock" flag */
         if ((flags & PARSE_FORWARD_LOCK) != 0) {
             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FORWARD_LOCK;
@@ -1105,7 +1106,6 @@
                 if (!parseUsesPermission(pkg, res, parser, attrs, outError)) {
                     return null;
                 }
-
             } else if (tagName.equals("uses-configuration")) {
                 ConfigurationInfo cPref = new ConfigurationInfo();
                 sa = res.obtainAttributes(attrs,
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 6f1d4f8..f53aa4c 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -71,7 +71,7 @@
     public static final int FLAG_MANAGED_PROFILE = 0x00000020;
 
 
-    public static final int NO_RELATED_GROUP_ID = -1;
+    public static final int NO_PROFILE_GROUP_ID = -1;
 
     public int id;
     public int serialNumber;
@@ -80,7 +80,7 @@
     public int flags;
     public long creationTime;
     public long lastLoggedInTime;
-    public int relatedGroupId;
+    public int profileGroupId;
 
     /** User is only partially created. */
     public boolean partial;
@@ -94,7 +94,7 @@
         this.name = name;
         this.flags = flags;
         this.iconPath = iconPath;
-        this.relatedGroupId = NO_RELATED_GROUP_ID;
+        this.profileGroupId = NO_PROFILE_GROUP_ID;
     }
 
     public boolean isPrimary() {
@@ -137,7 +137,7 @@
         creationTime = orig.creationTime;
         lastLoggedInTime = orig.lastLoggedInTime;
         partial = orig.partial;
-        relatedGroupId = orig.relatedGroupId;
+        profileGroupId = orig.profileGroupId;
     }
 
     public UserHandle getUserHandle() {
@@ -162,7 +162,7 @@
         dest.writeLong(creationTime);
         dest.writeLong(lastLoggedInTime);
         dest.writeInt(partial ? 1 : 0);
-        dest.writeInt(relatedGroupId);
+        dest.writeInt(profileGroupId);
     }
 
     public static final Parcelable.Creator<UserInfo> CREATOR
@@ -184,6 +184,6 @@
         creationTime = source.readLong();
         lastLoggedInTime = source.readLong();
         partial = source.readInt() != 0;
-        relatedGroupId = source.readInt();
+        profileGroupId = source.readInt();
     }
 }
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 419abf2..5674154 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -19,6 +19,7 @@
 import android.graphics.Color;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -181,10 +182,9 @@
         final int innerDepth = parser.getDepth()+1;
         int depth;
 
-        int listAllocated = 20;
+        int[][] stateSpecList = ArrayUtils.newUnpaddedArray(int[].class, 20);
+        int[] colorList = new int[stateSpecList.length];
         int listSize = 0;
-        int[] colorList = new int[listAllocated];
-        int[][] stateSpecList = new int[listAllocated][];
 
         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                && ((depth=parser.getDepth()) >= innerDepth
@@ -248,21 +248,8 @@
                 mDefaultColor = color;
             }
 
-            if (listSize + 1 >= listAllocated) {
-                listAllocated = ArrayUtils.idealIntArraySize(listSize + 1);
-
-                int[] ncolor = new int[listAllocated];
-                System.arraycopy(colorList, 0, ncolor, 0, listSize);
-
-                int[][] nstate = new int[listAllocated][];
-                System.arraycopy(stateSpecList, 0, nstate, 0, listSize);
-
-                colorList = ncolor;
-                stateSpecList = nstate;
-            }
-
-            colorList[listSize] = color;
-            stateSpecList[listSize] = stateSpec;
+            colorList = GrowingArrayUtils.append(colorList, listSize, color);
+            stateSpecList = GrowingArrayUtils.append(stateSpecList, listSize, stateSpec);
             listSize++;
         }
 
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index affc784..1955be3 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -114,7 +114,6 @@
     private boolean mPreloading;
 
     private TypedArray mCachedStyledAttributes = null;
-    private RuntimeException mLastRetrievedAttrs = null;
 
     private int mLastCachedXmlBlockIndex = -1;
     private final int[] mCachedXmlBlockIds = { 0, 0, 0, 0 };
@@ -1253,12 +1252,9 @@
         public void applyStyle(int resid, boolean force) {
             AssetManager.applyThemeStyle(mTheme, resid, force);
 
-            if (!mHasStyle) {
-                mHasStyle = true;
-                mThemeResId = resid;
-            } else if (resid != mThemeResId) {
-                mThemeResId = 0;
-            }
+            // TODO: In very rare cases, we may end up with a hybrid theme
+            // that can't map to a single theme ID.
+            mThemeResId = resid;
         }
 
         /**
@@ -1273,7 +1269,6 @@
         public void setTo(Theme other) {
             AssetManager.copyTheme(mTheme, other.mTheme);
 
-            mHasStyle = other.mHasStyle;
             mThemeResId = other.mThemeResId;
         }
 
@@ -1562,10 +1557,6 @@
             mAssets.releaseTheme(mTheme);
         }
 
-        /*package*/ boolean canCacheDrawables() {
-            return mHasStyle && mThemeResId != 0;
-        }
-
         /*package*/ Theme() {
             mAssets = Resources.this.mAssets;
             mTheme = mAssets.createTheme();
@@ -1575,12 +1566,8 @@
         private final AssetManager mAssets;
         private final long mTheme;
 
-        /**
-         * Resource identifier for the theme. If multiple styles have been
-         * applied to this theme, this value will be 0 (invalid).
-         */
+        /** Resource identifier for the theme. */
         private int mThemeResId = 0;
-        private boolean mHasStyle = false;
     }
 
     /**
@@ -2260,11 +2247,6 @@
             return;
         }
 
-        // Abort if the drawable is themed, but the theme cannot be cached.
-        if (dr.canApplyTheme() && theme != null && !theme.canCacheDrawables()) {
-            return;
-        }
-
         if (mPreloading) {
             // Preloaded drawables never have a theme, but may be themeable.
             final int changingConfigs = cs.getChangingConfigurations();
@@ -2289,11 +2271,7 @@
         } else {
             synchronized (mAccessLock) {
                 final LongSparseArray<WeakReference<ConstantState>> themedCache;
-                if (!dr.canApplyTheme()) {
-                    themedCache = caches.getUnthemed(true);
-                } else {
-                    themedCache = caches.getOrCreate(theme == null ? 0 : theme.mThemeResId);
-                }
+                themedCache = caches.getOrCreate(theme == null ? 0 : theme.mThemeResId);
                 themedCache.put(key, new WeakReference<ConstantState>(cs));
             }
         }
@@ -2354,21 +2332,6 @@
 
     private Drawable getCachedDrawable(ThemedCaches<ConstantState> caches, long key, Theme theme) {
         synchronized (mAccessLock) {
-            // First, check for a matching unthemed drawable.
-            final LongSparseArray<WeakReference<ConstantState>> unthemed = caches.getUnthemed(false);
-            if (unthemed != null) {
-                final Drawable unthemedDrawable = getCachedDrawableLocked(unthemed, key);
-                if (unthemedDrawable != null) {
-                    return unthemedDrawable;
-                }
-            }
-
-            final boolean themeCannotCache = theme != null && !theme.canCacheDrawables();
-            if (themeCannotCache) {
-                return null;
-            }
-
-            // Next, check for a matching themed drawable.
             final int themeKey = theme != null ? theme.mThemeResId : 0;
             final LongSparseArray<WeakReference<ConstantState>> themedCache = caches.get(themeKey);
             if (themedCache != null) {
@@ -2606,18 +2569,6 @@
     }
 
     static class ThemedCaches<T> extends SparseArray<LongSparseArray<WeakReference<T>>> {
-        private LongSparseArray<WeakReference<T>> mUnthemed = null;
-
-        /**
-         * Returns the cache of drawables with no themeable attributes.
-         */
-        public LongSparseArray<WeakReference<T>> getUnthemed(boolean autoCreate) {
-            if (mUnthemed == null && autoCreate) {
-                mUnthemed = new LongSparseArray<WeakReference<T>>(1);
-            }
-            return mUnthemed;
-        }
-
         /**
          * Returns the cache of drawables styled for the specified theme.
          * <p>
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 9fb2846..15337ce 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -32,7 +32,7 @@
  * {@link Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
  * or {@link Resources#obtainAttributes}.  Be
  * sure to call {@link #recycle} when done with them.
- * 
+ *
  * The indices used to retrieve values from this structure correspond to
  * the positions of the attributes given to obtainStyledAttributes.
  */
@@ -46,6 +46,7 @@
             attrs.mResources = res;
             attrs.mMetrics = res.getDisplayMetrics();
             attrs.mAssets = res.getAssets();
+            attrs.mRecycled = false;
 
             final int fullLen = len * AssetManager.STYLE_NUM_ENTRIES;
             if (attrs.mData.length >= fullLen) {
@@ -65,6 +66,8 @@
     private Resources mResources;
     private DisplayMetrics mMetrics;
     private AssetManager mAssets;
+    private boolean mRecycled;
+
     /*package*/ XmlBlock.Parser mXml;
     /*package*/ Resources.Theme mTheme;
     /*package*/ int[] mData;
@@ -76,45 +79,65 @@
      * Return the number of values in this array.
      */
     public int length() {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         return mLength;
     }
-    
+
     /**
      * Return the number of indices in the array that actually have data.
      */
     public int getIndexCount() {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         return mIndices[0];
     }
-    
+
     /**
      * Return an index in the array that has data.
-     * 
+     *
      * @param at The index you would like to returned, ranging from 0 to
      * {@link #getIndexCount()}.
-     * 
+     *
      * @return The index at the given offset, which can be used with
      * {@link #getValue} and related APIs.
      */
     public int getIndex(int at) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         return mIndices[1+at];
     }
-    
+
     /**
      * Return the Resources object this array was loaded from.
      */
     public Resources getResources() {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         return mResources;
     }
-    
+
     /**
      * Retrieve the styled string value for the attribute at <var>index</var>.
-     * 
+     *
      * @param index Index of attribute to retrieve.
-     * 
-     * @return CharSequence holding string data.  May be styled.  Returns 
+     *
+     * @return CharSequence holding string data.  May be styled.  Returns
      *         null if the attribute is not defined.
      */
     public CharSequence getText(int index) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
@@ -136,13 +159,17 @@
 
     /**
      * Retrieve the string value for the attribute at <var>index</var>.
-     * 
+     *
      * @param index Index of attribute to retrieve.
-     * 
+     *
      * @return String holding string data.  Any styling information is
      * removed.  Returns null if the attribute is not defined.
      */
     public String getString(int index) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
@@ -170,14 +197,18 @@
      * attributes, or conversions from other types.  As such, this method
      * will only return strings for TypedArray objects that come from
      * attributes in an XML file.
-     * 
+     *
      * @param index Index of attribute to retrieve.
-     * 
+     *
      * @return String holding string data.  Any styling information is
      * removed.  Returns null if the attribute is not defined or is not
      * an immediate string value.
      */
     public String getNonResourceString(int index) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
@@ -190,12 +221,12 @@
         }
         return null;
     }
-    
+
     /**
      * @hide
      * Retrieve the string value for the attribute at <var>index</var> that is
      * not allowed to change with the given configurations.
-     * 
+     *
      * @param index Index of attribute to retrieve.
      * @param allowedChangingConfigs Bit mask of configurations from
      * {@link Configuration}.NATIVE_CONFIG_* that are allowed to change.
@@ -204,6 +235,10 @@
      * removed.  Returns null if the attribute is not defined.
      */
     public String getNonConfigurationString(int index, int allowedChangingConfigs) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
@@ -229,13 +264,17 @@
 
     /**
      * Retrieve the boolean value for the attribute at <var>index</var>.
-     * 
+     *
      * @param index Index of attribute to retrieve.
      * @param defValue Value to return if the attribute is not defined.
-     * 
+     *
      * @return Attribute boolean value, or defValue if not defined.
      */
     public boolean getBoolean(int index, boolean defValue) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
@@ -259,13 +298,17 @@
 
     /**
      * Retrieve the integer value for the attribute at <var>index</var>.
-     * 
+     *
      * @param index Index of attribute to retrieve.
      * @param defValue Value to return if the attribute is not defined.
-     * 
+     *
      * @return Attribute int value, or defValue if not defined.
      */
     public int getInt(int index, int defValue) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
@@ -289,12 +332,16 @@
 
     /**
      * Retrieve the float value for the attribute at <var>index</var>.
-     * 
+     *
      * @param index Index of attribute to retrieve.
-     * 
+     *
      * @return Attribute float value, or defValue if not defined..
      */
     public float getFloat(int index, float defValue) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
@@ -319,20 +366,24 @@
               + Integer.toHexString(type));
         return defValue;
     }
-    
+
     /**
      * Retrieve the color value for the attribute at <var>index</var>.  If
      * the attribute references a color resource holding a complex
      * {@link android.content.res.ColorStateList}, then the default color from
      * the set is returned.
-     * 
+     *
      * @param index Index of attribute to retrieve.
      * @param defValue Value to return if the attribute is not defined or
      *                 not a resource.
-     * 
+     *
      * @return Attribute color value, or defValue if not defined.
      */
     public int getColor(int index, int defValue) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
@@ -359,12 +410,16 @@
      * Retrieve the ColorStateList for the attribute at <var>index</var>.
      * The value may be either a single solid color or a reference to
      * a color or complex {@link android.content.res.ColorStateList} description.
-     * 
+     *
      * @param index Index of attribute to retrieve.
-     * 
+     *
      * @return ColorStateList for the attribute, or null if not defined.
      */
     public ColorStateList getColorStateList(int index) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         final TypedValue value = mValue;
         if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             return mResources.loadColorStateList(value, value.resourceId);
@@ -374,14 +429,18 @@
 
     /**
      * Retrieve the integer value for the attribute at <var>index</var>.
-     * 
+     *
      * @param index Index of attribute to retrieve.
      * @param defValue Value to return if the attribute is not defined or
      *                 not a resource.
-     * 
+     *
      * @return Attribute integer value, or defValue if not defined.
      */
     public int getInteger(int index, int defValue) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
@@ -397,22 +456,26 @@
     }
 
     /**
-     * Retrieve a dimensional unit attribute at <var>index</var>.  Unit 
-     * conversions are based on the current {@link DisplayMetrics} 
-     * associated with the resources this {@link TypedArray} object 
-     * came from. 
-     * 
+     * Retrieve a dimensional unit attribute at <var>index</var>.  Unit
+     * conversions are based on the current {@link DisplayMetrics}
+     * associated with the resources this {@link TypedArray} object
+     * came from.
+     *
      * @param index Index of attribute to retrieve.
      * @param defValue Value to return if the attribute is not defined or
      *                 not a resource.
-     * 
-     * @return Attribute dimension value multiplied by the appropriate 
+     *
+     * @return Attribute dimension value multiplied by the appropriate
      * metric, or defValue if not defined.
-     * 
+     *
      * @see #getDimensionPixelOffset
      * @see #getDimensionPixelSize
      */
     public float getDimension(int index, float defValue) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
@@ -433,18 +496,22 @@
      * {@link #getDimension}, except the returned value is converted to
      * integer pixels for you.  An offset conversion involves simply
      * truncating the base value to an integer.
-     * 
+     *
      * @param index Index of attribute to retrieve.
      * @param defValue Value to return if the attribute is not defined or
      *                 not a resource.
-     * 
-     * @return Attribute dimension value multiplied by the appropriate 
+     *
+     * @return Attribute dimension value multiplied by the appropriate
      * metric and truncated to integer pixels, or defValue if not defined.
-     * 
+     *
      * @see #getDimension
      * @see #getDimensionPixelSize
      */
     public int getDimensionPixelOffset(int index, int defValue) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
@@ -466,18 +533,22 @@
      * integer pixels for use as a size.  A size conversion involves
      * rounding the base value, and ensuring that a non-zero base value
      * is at least one pixel in size.
-     * 
+     *
      * @param index Index of attribute to retrieve.
      * @param defValue Value to return if the attribute is not defined or
      *                 not a resource.
-     * 
-     * @return Attribute dimension value multiplied by the appropriate 
+     *
+     * @return Attribute dimension value multiplied by the appropriate
      * metric and truncated to integer pixels, or defValue if not defined.
-     *  
+     *
      * @see #getDimension
      * @see #getDimensionPixelOffset
      */
     public int getDimensionPixelSize(int index, int defValue) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
@@ -497,14 +568,18 @@
      * {@link android.view.ViewGroup}'s layout_width and layout_height
      * attributes.  This is only here for performance reasons; applications
      * should use {@link #getDimensionPixelSize}.
-     * 
+     *
      * @param index Index of the attribute to retrieve.
      * @param name Textual name of attribute for error reporting.
-     * 
-     * @return Attribute dimension value multiplied by the appropriate 
+     *
+     * @return Attribute dimension value multiplied by the appropriate
      * metric and truncated to integer pixels.
      */
     public int getLayoutDimension(int index, String name) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
@@ -519,21 +594,25 @@
         throw new RuntimeException(getPositionDescription()
                 + ": You must supply a " + name + " attribute.");
     }
-    
+
     /**
      * Special version of {@link #getDimensionPixelSize} for retrieving
      * {@link android.view.ViewGroup}'s layout_width and layout_height
      * attributes.  This is only here for performance reasons; applications
      * should use {@link #getDimensionPixelSize}.
-     * 
+     *
      * @param index Index of the attribute to retrieve.
      * @param defValue The default value to return if this attribute is not
      * default or contains the wrong type of data.
-     * 
-     * @return Attribute dimension value multiplied by the appropriate 
+     *
+     * @return Attribute dimension value multiplied by the appropriate
      * metric and truncated to integer pixels.
      */
     public int getLayoutDimension(int index, int defValue) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
@@ -550,20 +629,24 @@
 
     /**
      * Retrieve a fractional unit attribute at <var>index</var>.
-     * 
-     * @param index Index of attribute to retrieve. 
-     * @param base The base value of this fraction.  In other words, a 
+     *
+     * @param index Index of attribute to retrieve.
+     * @param base The base value of this fraction.  In other words, a
      *             standard fraction is multiplied by this value.
-     * @param pbase The parent base value of this fraction.  In other 
+     * @param pbase The parent base value of this fraction.  In other
      *             words, a parent fraction (nn%p) is multiplied by this
      *             value.
      * @param defValue Value to return if the attribute is not defined or
      *                 not a resource.
-     * 
-     * @return Attribute fractional value multiplied by the appropriate 
-     * base value, or defValue if not defined. 
+     *
+     * @return Attribute fractional value multiplied by the appropriate
+     * base value, or defValue if not defined.
      */
     public float getFraction(int index, int base, int pbase, float defValue) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
@@ -580,19 +663,23 @@
 
     /**
      * Retrieve the resource identifier for the attribute at
-     * <var>index</var>.  Note that attribute resource as resolved when 
-     * the overall {@link TypedArray} object is retrieved.  As a 
-     * result, this function will return the resource identifier of the 
-     * final resource value that was found, <em>not</em> necessarily the 
-     * original resource that was specified by the attribute. 
-     * 
+     * <var>index</var>.  Note that attribute resource as resolved when
+     * the overall {@link TypedArray} object is retrieved.  As a
+     * result, this function will return the resource identifier of the
+     * final resource value that was found, <em>not</em> necessarily the
+     * original resource that was specified by the attribute.
+     *
      * @param index Index of attribute to retrieve.
      * @param defValue Value to return if the attribute is not defined or
      *                 not a resource.
-     * 
+     *
      * @return Attribute resource identifier, or defValue if not defined.
      */
     public int getResourceId(int index, int defValue) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         if (data[index+AssetManager.STYLE_TYPE] != TypedValue.TYPE_NULL) {
@@ -615,6 +702,10 @@
      * @hide
      */
     public int getThemeAttributeId(int index, int defValue) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         if (data[index + AssetManager.STYLE_TYPE] == TypedValue.TYPE_ATTRIBUTE) {
@@ -628,12 +719,16 @@
      * gets the resource ID of the selected attribute, and uses
      * {@link Resources#getDrawable Resources.getDrawable} of the owning
      * Resources object to retrieve its Drawable.
-     * 
+     *
      * @param index Index of attribute to retrieve.
-     * 
+     *
      * @return Drawable for the attribute, or null if not defined.
      */
     public Drawable getDrawable(int index) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         final TypedValue value = mValue;
         if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             if (false) {
@@ -655,12 +750,16 @@
      * This gets the resource ID of the selected attribute, and uses
      * {@link Resources#getTextArray Resources.getTextArray} of the owning
      * Resources object to retrieve its String[].
-     * 
+     *
      * @param index Index of attribute to retrieve.
-     * 
+     *
      * @return CharSequence[] for the attribute, or null if not defined.
      */
     public CharSequence[] getTextArray(int index) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         final TypedValue value = mValue;
         if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             if (false) {
@@ -679,36 +778,19 @@
 
     /**
      * Retrieve the raw TypedValue for the attribute at <var>index</var>.
-     * 
+     *
      * @param index Index of attribute to retrieve.
      * @param outValue TypedValue object in which to place the attribute's
      *                 data.
-     * 
-     * @return Returns true if the value was retrieved, else false. 
+     *
+     * @return Returns true if the value was retrieved, else false.
      */
     public boolean getValue(int index, TypedValue outValue) {
-        return getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, outValue);
-    }
-
-    /**
-     * Determines whether this TypedArray contains an attribute of the specified
-     * type.
-     *
-     * @param type Type of data, e.g. {@link TypedValue#TYPE_ATTRIBUTE}
-     * @return True if the TypedArray contains an attribute of the specified
-     *         type.
-     * @hide
-     */
-    public boolean hasType(int type) {
-        final int[] data = mData;
-        final int N = getIndexCount();
-        for (int i = 0; i < N; i++) {
-            final int index = getIndex(i) * AssetManager.STYLE_NUM_ENTRIES;
-            if (data[index + AssetManager.STYLE_TYPE] == type) {
-                return true;
-            }
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
-        return false;
+
+        return getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, outValue);
     }
 
     /**
@@ -718,36 +800,48 @@
      * @return Attribute type.
      */
     public int getType(int index) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         return mData[index + AssetManager.STYLE_TYPE];
     }
 
     /**
      * Determines whether there is an attribute at <var>index</var>.
-     * 
+     *
      * @param index Index of attribute to retrieve.
-     * 
+     *
      * @return True if the attribute has a value, false otherwise.
      */
     public boolean hasValue(int index) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
         return type != TypedValue.TYPE_NULL;
     }
-    
+
     /**
-     * Retrieve the raw TypedValue for the attribute at <var>index</var> 
-     * and return a temporary object holding its data.  This object is only 
-     * valid until the next call on to {@link TypedArray}. 
-     * 
+     * Retrieve the raw TypedValue for the attribute at <var>index</var>
+     * and return a temporary object holding its data.  This object is only
+     * valid until the next call on to {@link TypedArray}.
+     *
      * @param index Index of attribute to retrieve.
-     * 
-     * @return Returns a TypedValue object if the attribute is defined, 
+     *
+     * @return Returns a TypedValue object if the attribute is defined,
      *         containing its data; otherwise returns null.  (You will not
      *         receive a TypedValue whose type is TYPE_NULL.)
      */
     public TypedValue peekValue(int index) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         final TypedValue value = mValue;
         if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             return value;
@@ -759,13 +853,23 @@
      * Returns a message about the parser state suitable for printing error messages.
      */
     public String getPositionDescription() {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         return mXml != null ? mXml.getPositionDescription() : "<internal>";
     }
 
     /**
-     * Give back a previously retrieved array, for later re-use.
+     * Recycle the TypedArray, to be re-used by a later caller. After calling
+     * this function you must not ever touch the typed array again.
      */
     public void recycle() {
+        if (mRecycled) {
+            throw new RuntimeException(toString() + " recycled twice!");
+        }
+
+        mRecycled = true;
         mResources = null;
         mMetrics = null;
         mAssets = null;
@@ -791,6 +895,10 @@
      * @hide
      */
     public int[] extractThemeAttrs() {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         int[] attrs = null;
 
         final int N = length();
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 37bead8..ff77580 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1093,8 +1093,8 @@
      *
      * @see CaptureRequest#SENSOR_TEST_PATTERN_MODE
      */
-    public static final Key<Byte> SENSOR_AVAILABLE_TEST_PATTERN_MODES =
-            new Key<Byte>("android.sensor.availableTestPatternModes", byte.class);
+    public static final Key<int[]> SENSOR_AVAILABLE_TEST_PATTERN_MODES =
+            new Key<int[]>("android.sensor.availableTestPatternModes", int[].class);
 
     /**
      * <p>Which face detection modes are available,
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 42c8e3d..679310a 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1002,8 +1002,11 @@
      * controls; the camera device will ignore those settings while
      * USE_SCENE_MODE is active (except for FACE_PRIORITY
      * scene mode). Other control entries are still active.
-     * This setting can only be used if availableSceneModes !=
-     * UNSUPPORTED</p>
+     * This setting can only be used if scene mode is supported
+     * (i.e. {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes} contain some modes
+     * other than DISABLED).</p>
+     *
+     * @see CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES
      * @see CaptureRequest#CONTROL_MODE
      */
     public static final int CONTROL_MODE_USE_SCENE_MODE = 2;
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index 2c8a5c2..ecc461e 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -335,7 +335,9 @@
                 mRepeatingRequestId = REQUEST_ID_NONE;
 
                 // Queue for deletion after in-flight requests finish
-                mRepeatingRequestIdDeletedList.add(requestId);
+                if (mCaptureListenerMap.get(requestId) != null) {
+                    mRepeatingRequestIdDeletedList.add(requestId);
+                }
 
                 try {
                     mRemoteDevice.cancelRequest(requestId);
@@ -367,8 +369,6 @@
             }
 
             mRepeatingRequestId = REQUEST_ID_NONE;
-            mRepeatingRequestIdDeletedList.clear();
-            mCaptureListenerMap.clear();
         }
     }
 
diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java
index a500bcf..830ddce 100644
--- a/core/java/android/net/http/X509TrustManagerExtensions.java
+++ b/core/java/android/net/http/X509TrustManagerExtensions.java
@@ -56,7 +56,8 @@
         if (tm instanceof TrustManagerImpl) {
             mDelegate = (TrustManagerImpl) tm;
         } else {
-            throw new IllegalArgumentException("tm is not a supported type of X509TrustManager");
+            throw new IllegalArgumentException("tm is an instance of " + tm.getClass().getName() +
+                    " which is not a supported type of X509TrustManager");
         }
     }
 
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 6e6c06d..1192a45 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -28,13 +28,13 @@
  */
 interface IUserManager {
     UserInfo createUser(in String name, int flags);
-    UserInfo createRelatedUser(in String name, int flags, int relatedUserId);
+    UserInfo createProfileForUser(in String name, int flags, int userHandle);
     boolean removeUser(int userHandle);
     void setUserName(int userHandle, String name);
     void setUserIcon(int userHandle, in Bitmap icon);
     Bitmap getUserIcon(int userHandle);
     List<UserInfo> getUsers(boolean excludeDying);
-    List<UserInfo> getRelatedUsers(int userHandle);
+    List<UserInfo> getProfiles(int userHandle);
     UserInfo getUserInfo(int userHandle);
     boolean isRestricted();
     void setGuestEnabled(boolean enable);
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 057f516..3241693 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -16,10 +16,11 @@
 
 package android.os;
 
-import android.net.LocalSocketAddress;
 import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
 import android.util.Log;
-import dalvik.system.Zygote;
+
+import com.android.internal.os.Zygote;
 
 import java.io.BufferedWriter;
 import java.io.DataInputStream;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1ec5cd5..520a08c 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -410,20 +410,29 @@
     }
 
     /**
-     * Creates a user with the specified name and options.
+     * Renamed, just present to avoid multi project commit.
+     * TODO delete.
+     * @hide
+     */
+    public UserInfo createRelatedUser(String name, int flags, int relatedUserId) {
+        return createProfileForUser(name, flags, relatedUserId);
+    }
+
+    /**
+     * Creates a user with the specified name and options as a profile of another user.
      * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      *
      * @param name the user's name
      * @param flags flags that identify the type of user and other properties.
      * @see UserInfo
-     * @param relatedUserId new user will be related to this user id.
+     * @param userHandle new user will be a profile of this use.
      *
      * @return the UserInfo object for the created user, or null if the user could not be created.
      * @hide
      */
-    public UserInfo createRelatedUser(String name, int flags, int relatedUserId) {
+    public UserInfo createProfileForUser(String name, int flags, int userHandle) {
         try {
-            return mService.createRelatedUser(name, flags, relatedUserId);
+            return mService.createProfileForUser(name, flags, userHandle);
         } catch (RemoteException re) {
             Log.w(TAG, "Could not create a user", re);
             return null;
@@ -454,15 +463,26 @@
     }
 
     /**
-     * Returns information for all users related to userId
-     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
-     * @param userHandle users related to this user id will be returned.
-     * @return the list of related users.
+     * Renaming, left to avoid multi project commit.
+     * TODO Delete.
      * @hide
      */
     public List<UserInfo> getRelatedUsers(int userHandle) {
+        return getProfiles(userHandle);
+    }
+
+    /**
+     * Returns list of the profiles of userHandle including
+     * userHandle itself.
+     * 
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+     * @param userHandle profiles of this user will be returned.
+     * @return the list of profiles.
+     * @hide
+     */
+    public List<UserInfo> getProfiles(int userHandle) {
         try {
-            return mService.getRelatedUsers(userHandle);
+            return mService.getProfiles(userHandle);
         } catch (RemoteException re) {
             Log.w(TAG, "Could not get user list", re);
             return null;
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index b97734e..4180860 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -694,6 +694,36 @@
                 return _result;
             }
 
+            public String getPassword() throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                String _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    mRemote.transact(Stub.TRANSACTION_getPassword, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readString();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            public void clearPassword() throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                String _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    mRemote.transact(Stub.TRANSACTION_clearPassword, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
             public StorageVolume[] getVolumeList() throws RemoteException {
                 Parcel _data = Parcel.obtain();
                 Parcel _reply = Parcel.obtain();
@@ -846,7 +876,11 @@
 
         static final int TRANSACTION_mkdirs = IBinder.FIRST_CALL_TRANSACTION + 34;
 
-        static final int TRANSACTION_getPasswordType = IBinder.FIRST_CALL_TRANSACTION + 36;
+        static final int TRANSACTION_getPasswordType = IBinder.FIRST_CALL_TRANSACTION + 35;
+
+        static final int TRANSACTION_getPassword = IBinder.FIRST_CALL_TRANSACTION + 36;
+
+        static final int TRANSACTION_clearPassword = IBinder.FIRST_CALL_TRANSACTION + 37;
 
         /**
          * Cast an IBinder object into an IMountService interface, generating a
@@ -1208,6 +1242,19 @@
                     reply.writeInt(result);
                     return true;
                 }
+                case TRANSACTION_getPassword: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String result = getPassword();
+                    reply.writeNoException();
+                    reply.writeString(result);
+                    return true;
+                }
+                case TRANSACTION_clearPassword: {
+                    data.enforceInterface(DESCRIPTOR);
+                    clearPassword();
+                    reply.writeNoException();
+                    return true;
+                }
             }
             return super.onTransact(code, data, reply, flags);
         }
@@ -1446,4 +1493,15 @@
      * @return PasswordType
      */
     public int getPasswordType() throws RemoteException;
+
+    /**
+     * Get password from vold
+     * @return password or empty string
+     */
+    public String getPassword() throws RemoteException;
+
+    /**
+     * Securely clear password from vold
+     */
+    public void clearPassword() throws RemoteException;
 }
diff --git a/core/java/android/provider/SearchIndexablesContract.java b/core/java/android/provider/SearchIndexablesContract.java
index b8635b8..05f3a1c 100644
--- a/core/java/android/provider/SearchIndexablesContract.java
+++ b/core/java/android/provider/SearchIndexablesContract.java
@@ -73,7 +73,8 @@
     public static final String[] INDEXABLES_RAW_COLUMNS = new String[] {
             RawData.COLUMN_RANK,
             RawData.COLUMN_TITLE,
-            RawData.COLUMN_SUMMARY,
+            RawData.COLUMN_SUMMARY_ON,
+            RawData.COLUMN_SUMMARY_OFF,
             RawData.COLUMN_KEYWORDS,
             RawData.COLUMN_SCREEN_TITLE,
             RawData.COLUMN_CLASS_NAME,
@@ -123,9 +124,14 @@
         public static final String COLUMN_TITLE = "title";
 
         /**
-         * Summary's raw data.
+         * Summary's raw data when the data is "ON".
          */
-        public static final String COLUMN_SUMMARY = "summary";
+        public static final String COLUMN_SUMMARY_ON = "summaryOn";
+
+        /**
+         * Summary's raw data when the data is "OFF".
+         */
+        public static final String COLUMN_SUMMARY_OFF = "summaryOff";
 
         /**
          * Keywords' raw data.
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index 425fdc1..d4b29d8 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -21,6 +21,7 @@
 /** @hide */
 oneway interface INotificationListener
 {
+    void onListenerConnected(in String[] notificationKeys);
     void onNotificationPosted(in StatusBarNotification notification);
     void onNotificationRemoved(in StatusBarNotification notification);
 }
\ No newline at end of file
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index cf862b8..050e1a0 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -83,6 +83,17 @@
      */
     public abstract void onNotificationRemoved(StatusBarNotification sbn);
 
+    /**
+     * Implement this method to learn about when the listener is enabled and connected to
+     * the notification manager.  You are safe to call {@link #getActiveNotifications(String[])
+     * at this time.
+     *
+     * @param notificationKeys The notification keys for all currently posted notifications.
+     */
+    public void onListenerConnected(String[] notificationKeys) {
+        // optional
+    }
+
     private final INotificationManager getNotificationInterface() {
         if (mNoMan == null) {
             mNoMan = INotificationManager.Stub.asInterface(
@@ -132,9 +143,23 @@
      * {@see #cancelNotification(String, String, int)}
      */
     public final void cancelAllNotifications() {
+        cancelNotifications(null /*all*/);
+    }
+
+    /**
+     * Inform the notification manager about dismissal of specific notifications.
+     * <p>
+     * Use this if your listener has a user interface that allows the user to dismiss
+     * multiple notifications at once.
+     *
+     * @param keys Notifications to dismiss, or {@code null} to dismiss all.
+     *
+     * {@see #cancelNotification(String, String, int)}
+     */
+    public final void cancelNotifications(String[] keys) {
         if (!isBound()) return;
         try {
-            getNotificationInterface().cancelAllNotificationsFromListener(mWrapper);
+            getNotificationInterface().cancelNotificationsFromListener(mWrapper, keys);
         } catch (android.os.RemoteException ex) {
             Log.v(TAG, "Unable to contact notification manager", ex);
         }
@@ -142,14 +167,43 @@
 
     /**
      * Request the list of outstanding notifications (that is, those that are visible to the
-     * current user). Useful when starting up and you don't know what's already been posted.
+     * current user). Useful when you don't know what's already been posted.
      *
      * @return An array of active notifications.
      */
     public StatusBarNotification[] getActiveNotifications() {
+        return getActiveNotifications(null /*all*/);
+    }
+
+    /**
+     * Request the list of outstanding notifications (that is, those that are visible to the
+     * current user). Useful when you don't know what's already been posted.
+     *
+     * @param keys A specific list of notification keys, or {@code null} for all.
+     * @return An array of active notifications.
+     */
+    public StatusBarNotification[] getActiveNotifications(String[] keys) {
         if (!isBound()) return null;
         try {
-            return getNotificationInterface().getActiveNotificationsFromListener(mWrapper);
+            return getNotificationInterface().getActiveNotificationsFromListener(mWrapper, keys);
+        } catch (android.os.RemoteException ex) {
+            Log.v(TAG, "Unable to contact notification manager", ex);
+        }
+        return null;
+    }
+
+    /**
+     * Request the list of outstanding notification keys(that is, those that are visible to the
+     * current user).  You can use the notification keys for subsequent retrieval via
+     * {@link #getActiveNotifications(String[]) or dismissal via
+     * {@link #cancelNotifications(String[]).
+     *
+     * @return An array of active notification keys.
+     */
+    public String[] getActiveNotificationKeys() {
+        if (!isBound()) return null;
+        try {
+            return getNotificationInterface().getActiveNotificationKeysFromListener(mWrapper);
         } catch (android.os.RemoteException ex) {
             Log.v(TAG, "Unable to contact notification manager", ex);
         }
@@ -189,5 +243,13 @@
                 Log.w(TAG, "Error running onNotificationRemoved", t);
             }
         }
+        @Override
+        public void onListenerConnected(String[] notificationKeys) {
+            try {
+                NotificationListenerService.this.onListenerConnected(notificationKeys);
+            } catch (Throwable t) {
+                Log.w(TAG, "Error running onListenerConnected", t);
+            }
+        }
     }
 }
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index b5b9e14..7f15ab8 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -29,6 +29,7 @@
     private final String pkg;
     private final int id;
     private final String tag;
+    private final String key;
 
     private final int uid;
     private final String basePkg;
@@ -68,8 +69,8 @@
         this.notification = notification;
         this.user = user;
         this.notification.setUser(user);
-
         this.postTime = postTime;
+        this.key = key();
     }
 
     public StatusBarNotification(Parcel in) {
@@ -88,6 +89,11 @@
         this.user = UserHandle.readFromParcel(in);
         this.notification.setUser(this.user);
         this.postTime = in.readLong();
+        this.key = key();
+    }
+
+    private String key() {
+        return pkg + '|' + basePkg + '|' + id + '|' + tag + '|' + uid;
     }
 
     public void writeToParcel(Parcel out, int flags) {
@@ -148,9 +154,9 @@
     @Override
     public String toString() {
         return String.format(
-                "StatusBarNotification(pkg=%s user=%s id=%d tag=%s score=%d: %s)",
+                "StatusBarNotification(pkg=%s user=%s id=%d tag=%s score=%d key=%s: %s)",
                 this.pkg, this.user, this.id, this.tag,
-                this.score, this.notification);
+                this.score, this.key, this.notification);
     }
 
     /** Convenience method to check the notification's flags for
@@ -230,4 +236,11 @@
     public int getScore() {
         return score;
     }
+
+    /**
+     * A unique instance key for this notification record.
+     */
+    public String getKey() {
+        return key;
+    }
 }
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/service/trust/ITrustAgentService.aidl
similarity index 64%
copy from core/java/android/view/DisplayList.java
copy to core/java/android/service/trust/ITrustAgentService.aidl
index ed52803..863a249 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/service/trust/ITrustAgentService.aidl
@@ -13,13 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.service.trust;
 
-package android.view;
+import android.os.Bundle;
+import android.service.trust.ITrustAgentServiceCallback;
 
-/** TODO: Remove once frameworks/webview is updated
- *  @hide
+/**
+ * Communication channel from TrustManagerService to the TrustAgent.
+ * @hide
  */
-public class DisplayList {
-    /** @hide */
-    public static final int STATUS_DONE = 0x0;
+oneway interface ITrustAgentService {
+    void onUnlockAttempt(boolean successful);
+    void setCallback(ITrustAgentServiceCallback callback);
 }
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
similarity index 64%
rename from core/java/android/view/DisplayList.java
rename to core/java/android/service/trust/ITrustAgentServiceCallback.aidl
index ed52803..c346771 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
@@ -13,13 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.service.trust;
 
-package android.view;
+import android.os.Bundle;
+import android.os.UserHandle;
 
-/** TODO: Remove once frameworks/webview is updated
- *  @hide
+/**
+ * Communication channel from the TrustAgentService back to TrustManagerService.
+ * @hide
  */
-public class DisplayList {
-    /** @hide */
-    public static final int STATUS_DONE = 0x0;
+oneway interface ITrustAgentServiceCallback {
+    void enableTrust(String message, long durationMs, boolean initiatedByUser);
+    void revokeTrust();
 }
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
new file mode 100644
index 0000000..d5ce429
--- /dev/null
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -0,0 +1,148 @@
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.trust;
+
+import android.annotation.SdkConstant;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+/**
+ * A service that notifies the system about whether it believes the environment of the device
+ * to be trusted.
+ *
+ * <p>To extend this class, you must declare the service in your manifest file with
+ * the {@link android.Manifest.permission#BIND_TRUST_AGENT_SERVICE} permission
+ * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
+ * <pre>
+ * &lt;service android:name=".TrustAgent"
+ *          android:label="&#64;string/service_name"
+ *          android:permission="android.permission.BIND_TRUST_AGENT_SERVICE">
+ *     &lt;intent-filter>
+ *         &lt;action android:name="android.service.trust.TrustAgentService" />
+ *     &lt;/intent-filter>
+ *     &lt;meta-data android:name="android.service.trust.trustagent"
+ *          android:value="&#64;xml/trust_agent" />
+ * &lt;/service></pre>
+ *
+ * <p>The associated meta-data file can specify an activity that is accessible through Settings
+ * and should allow configuring the trust agent, as defined in
+ * {@link android.R.styleable#TrustAgent}. For example:</p>
+ *
+ * <pre>
+ * &lt;trust_agent xmlns:android="http://schemas.android.com/apk/res/android"
+ *          android:settingsActivity=".TrustAgentSettings" /></pre>
+ */
+public class TrustAgentService extends Service {
+    private final String TAG = TrustAgentService.class.getSimpleName() +
+            "[" + getClass().getSimpleName() + "]";
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE
+            = "android.service.trust.TrustAgentService";
+
+    /**
+     * The name of the {@code meta-data} tag pointing to additional configuration of the trust
+     * agent.
+     */
+    public static final String TRUST_AGENT_META_DATA = "android.service.trust.trustagent";
+
+    private static final int MSG_UNLOCK_ATTEMPT = 1;
+
+    private static final boolean DEBUG = false;
+
+    private ITrustAgentServiceCallback mCallback;
+
+    private Handler mHandler = new Handler() {
+        public void handleMessage(android.os.Message msg) {
+            switch (msg.what) {
+                case MSG_UNLOCK_ATTEMPT:
+                    onUnlockAttempt(msg.arg1 != 0);
+                    break;
+            }
+        };
+    };
+
+    /**
+     * Called when the user attempted to authenticate on the device.
+     *
+     * @param successful true if the attempt succeeded
+     */
+    protected void onUnlockAttempt(boolean successful) {
+    }
+
+    private void onError(String msg) {
+        Slog.v(TAG, "Remote exception while " + msg);
+    }
+
+    /**
+     * Call to enable trust on the device.
+     *
+     * @param message describes why the device is trusted, e.g. "Trusted by location".
+     * @param durationMs amount of time in milliseconds to keep the device in a trusted state. Trust
+     *                   for this agent will automatically be revoked when the timeout expires.
+     * @param initiatedByUser indicates that the user has explicitly initiated an action that proves
+     *                        the user is about to use the device.
+     */
+    protected final void enableTrust(String message, long durationMs, boolean initiatedByUser) {
+        if (mCallback != null) {
+            try {
+                mCallback.enableTrust(message, durationMs, initiatedByUser);
+            } catch (RemoteException e) {
+                onError("calling enableTrust()");
+            }
+        }
+    }
+
+    /**
+     * Call to revoke trust on the device.
+     */
+    protected final void revokeTrust() {
+        if (mCallback != null) {
+            try {
+                mCallback.revokeTrust();
+            } catch (RemoteException e) {
+                onError("calling revokeTrust()");
+            }
+        }
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
+        return new TrustAgentServiceWrapper();
+    }
+
+    private final class TrustAgentServiceWrapper extends ITrustAgentService.Stub {
+        @Override
+        public void onUnlockAttempt(boolean successful) {
+            mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0)
+                    .sendToTarget();
+        }
+
+        public void setCallback(ITrustAgentServiceCallback callback) {
+            mCallback = callback;
+        }
+    }
+
+}
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 06935ae..77ef1da 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -21,6 +21,7 @@
 import android.text.style.WrapTogetherSpan;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
 
 import java.lang.ref.WeakReference;
 
@@ -401,7 +402,7 @@
 
         if (mBlockEndLines == null) {
             // Initial creation of the array, no test on previous block ending line
-            mBlockEndLines = new int[ArrayUtils.idealIntArraySize(1)];
+            mBlockEndLines = ArrayUtils.newUnpaddedIntArray(1);
             mBlockEndLines[mNumberOfBlocks] = line;
             mNumberOfBlocks++;
             return;
@@ -409,13 +410,7 @@
 
         final int previousBlockEndLine = mBlockEndLines[mNumberOfBlocks - 1];
         if (line > previousBlockEndLine) {
-            if (mNumberOfBlocks == mBlockEndLines.length) {
-                // Grow the array if needed
-                int[] blockEndLines = new int[ArrayUtils.idealIntArraySize(mNumberOfBlocks + 1)];
-                System.arraycopy(mBlockEndLines, 0, blockEndLines, 0, mNumberOfBlocks);
-                mBlockEndLines = blockEndLines;
-            }
-            mBlockEndLines[mNumberOfBlocks] = line;
+            mBlockEndLines = GrowingArrayUtils.append(mBlockEndLines, mNumberOfBlocks, line);
             mNumberOfBlocks++;
         }
     }
@@ -483,9 +478,9 @@
         }
 
         if (newNumberOfBlocks > mBlockEndLines.length) {
-            final int newSize = ArrayUtils.idealIntArraySize(newNumberOfBlocks);
-            int[] blockEndLines = new int[newSize];
-            int[] blockIndices = new int[newSize];
+            int[] blockEndLines = ArrayUtils.newUnpaddedIntArray(
+                    Math.max(mBlockEndLines.length * 2, newNumberOfBlocks));
+            int[] blockIndices = new int[blockEndLines.length];
             System.arraycopy(mBlockEndLines, 0, blockEndLines, 0, firstBlock);
             System.arraycopy(mBlockIndices, 0, blockIndices, 0, firstBlock);
             System.arraycopy(mBlockEndLines, lastBlock + 1,
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index c80321c..2fcc597 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -211,7 +211,7 @@
 
     private static String getOpenParaTagWithDirection(Spanned text, int start, int end) {
         final int len = end - start;
-        final byte[] levels = new byte[ArrayUtils.idealByteArraySize(len)];
+        final byte[] levels = ArrayUtils.newUnpaddedByteArray(len);
         final char[] buffer = TextUtils.obtain(len);
         TextUtils.getChars(text, start, end, buffer, 0);
 
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 9dfd383..4bfcaff 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -31,6 +31,7 @@
 import android.text.style.TabStopSpan;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
 
 import java.util.Arrays;
 
@@ -403,14 +404,9 @@
                                 // construction
                                 if (mLineBackgroundSpans.spanStarts[j] >= end ||
                                         mLineBackgroundSpans.spanEnds[j] <= start) continue;
-                                if (spansLength == spans.length) {
-                                    // The spans array needs to be expanded
-                                    int newSize = ArrayUtils.idealObjectArraySize(2 * spansLength);
-                                    ParagraphStyle[] newSpans = new ParagraphStyle[newSize];
-                                    System.arraycopy(spans, 0, newSpans, 0, spansLength);
-                                    spans = newSpans;
-                                }
-                                spans[spansLength++] = mLineBackgroundSpans.spans[j];
+                                spans = GrowingArrayUtils.append(
+                                        spans, spansLength, mLineBackgroundSpans.spans[j]);
+                                spansLength++;
                             }
                         }
                     }
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index 101d6a2..f8e3c83 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -98,10 +98,10 @@
         mPos = 0;
 
         if (mWidths == null || mWidths.length < len) {
-            mWidths = new float[ArrayUtils.idealFloatArraySize(len)];
+            mWidths = ArrayUtils.newUnpaddedFloatArray(len);
         }
         if (mChars == null || mChars.length < len) {
-            mChars = new char[ArrayUtils.idealCharArraySize(len)];
+            mChars = ArrayUtils.newUnpaddedCharArray(len);
         }
         TextUtils.getChars(text, start, end, mChars, 0);
 
@@ -130,7 +130,7 @@
             mEasy = true;
         } else {
             if (mLevels == null || mLevels.length < len) {
-                mLevels = new byte[ArrayUtils.idealByteArraySize(len)];
+                mLevels = ArrayUtils.newUnpaddedByteArray(len);
             }
             int bidiRequest;
             if (textDir == TextDirectionHeuristics.LTR) {
diff --git a/core/java/android/text/PackedIntVector.java b/core/java/android/text/PackedIntVector.java
index d87f600..546ab44 100644
--- a/core/java/android/text/PackedIntVector.java
+++ b/core/java/android/text/PackedIntVector.java
@@ -17,6 +17,7 @@
 package android.text;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
 
 
 /**
@@ -252,9 +253,9 @@
      */
     private final void growBuffer() {
         final int columns = mColumns;
-        int newsize = size() + 1;
-        newsize = ArrayUtils.idealIntArraySize(newsize * columns) / columns;
-        int[] newvalues = new int[newsize * columns];
+        int[] newvalues = ArrayUtils.newUnpaddedIntArray(
+                GrowingArrayUtils.growSize(size()) * columns);
+        int newsize = newvalues.length / columns;
 
         final int[] valuegap = mValueGap;
         final int rowgapstart = mRowGapStart;
diff --git a/core/java/android/text/PackedObjectVector.java b/core/java/android/text/PackedObjectVector.java
index a29df09..b777e16 100644
--- a/core/java/android/text/PackedObjectVector.java
+++ b/core/java/android/text/PackedObjectVector.java
@@ -17,6 +17,9 @@
 package android.text;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
 
 class PackedObjectVector<E>
 {
@@ -32,12 +35,11 @@
     PackedObjectVector(int columns)
     {
         mColumns = columns;
-        mRows = ArrayUtils.idealIntArraySize(0) / mColumns;
+        mValues = EmptyArray.OBJECT;
+        mRows = 0;
 
         mRowGapStart = 0;
         mRowGapLength = mRows;
-
-        mValues = new Object[mRows * mColumns];
     }
 
     public E
@@ -109,10 +111,9 @@
     private void
     growBuffer()
     {
-        int newsize = size() + 1;
-        newsize = ArrayUtils.idealIntArraySize(newsize * mColumns) / mColumns;
-        Object[] newvalues = new Object[newsize * mColumns];
-
+        Object[] newvalues = ArrayUtils.newUnpaddedObjectArray(
+                GrowingArrayUtils.growSize(size()) * mColumns);
+        int newsize = newvalues.length / mColumns;
         int after = mRows - (mRowGapStart + mRowGapLength);
 
         System.arraycopy(mValues, 0, newvalues, 0, mColumns * mRowGapStart);
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index b55cd6a..f440853 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -21,6 +21,9 @@
 import android.util.Log;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
 
 import java.lang.reflect.Array;
 
@@ -54,19 +57,17 @@
 
         if (srclen < 0) throw new StringIndexOutOfBoundsException();
 
-        int len = ArrayUtils.idealCharArraySize(srclen + 1);
-        mText = new char[len];
+        mText = ArrayUtils.newUnpaddedCharArray(GrowingArrayUtils.growSize(srclen));
         mGapStart = srclen;
-        mGapLength = len - srclen;
+        mGapLength = mText.length - srclen;
 
         TextUtils.getChars(text, start, end, mText, 0);
 
         mSpanCount = 0;
-        int alloc = ArrayUtils.idealIntArraySize(0);
-        mSpans = new Object[alloc];
-        mSpanStarts = new int[alloc];
-        mSpanEnds = new int[alloc];
-        mSpanFlags = new int[alloc];
+        mSpans = EmptyArray.OBJECT;
+        mSpanStarts = EmptyArray.INT;
+        mSpanEnds = EmptyArray.INT;
+        mSpanFlags = EmptyArray.INT;
 
         if (text instanceof Spanned) {
             Spanned sp = (Spanned) text;
@@ -130,12 +131,14 @@
 
     private void resizeFor(int size) {
         final int oldLength = mText.length;
-        final int newLength = ArrayUtils.idealCharArraySize(size + 1);
-        final int delta = newLength - oldLength;
-        if (delta == 0) return;
+        if (size + 1 <= oldLength) {
+            return;
+        }
 
-        char[] newText = new char[newLength];
+        char[] newText = ArrayUtils.newUnpaddedCharArray(GrowingArrayUtils.growSize(size));
         System.arraycopy(mText, 0, newText, 0, mGapStart);
+        final int newLength = newText.length;
+        final int delta = newLength - oldLength;
         final int after = oldLength - (mGapStart + mGapLength);
         System.arraycopy(mText, oldLength - after, newText, newLength - after, after);
         mText = newText;
@@ -679,28 +682,10 @@
             }
         }
 
-        if (mSpanCount + 1 >= mSpans.length) {
-            int newsize = ArrayUtils.idealIntArraySize(mSpanCount + 1);
-            Object[] newspans = new Object[newsize];
-            int[] newspanstarts = new int[newsize];
-            int[] newspanends = new int[newsize];
-            int[] newspanflags = new int[newsize];
-
-            System.arraycopy(mSpans, 0, newspans, 0, mSpanCount);
-            System.arraycopy(mSpanStarts, 0, newspanstarts, 0, mSpanCount);
-            System.arraycopy(mSpanEnds, 0, newspanends, 0, mSpanCount);
-            System.arraycopy(mSpanFlags, 0, newspanflags, 0, mSpanCount);
-
-            mSpans = newspans;
-            mSpanStarts = newspanstarts;
-            mSpanEnds = newspanends;
-            mSpanFlags = newspanflags;
-        }
-
-        mSpans[mSpanCount] = what;
-        mSpanStarts[mSpanCount] = start;
-        mSpanEnds[mSpanCount] = end;
-        mSpanFlags[mSpanCount] = flags;
+        mSpans = GrowingArrayUtils.append(mSpans, mSpanCount, what);
+        mSpanStarts = GrowingArrayUtils.append(mSpanStarts, mSpanCount, start);
+        mSpanEnds = GrowingArrayUtils.append(mSpanEnds, mSpanCount, end);
+        mSpanFlags = GrowingArrayUtils.append(mSpanFlags, mSpanCount, flags);
         mSpanCount++;
 
         if (send) sendSpanAdded(what, nstart, nend);
diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java
index 456a3e5..d114d32 100644
--- a/core/java/android/text/SpannableStringInternal.java
+++ b/core/java/android/text/SpannableStringInternal.java
@@ -17,6 +17,9 @@
 package android.text;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
 
 import java.lang.reflect.Array;
 
@@ -29,9 +32,8 @@
         else
             mText = source.toString().substring(start, end);
 
-        int initial = ArrayUtils.idealIntArraySize(0);
-        mSpans = new Object[initial];
-        mSpanData = new int[initial * 3];
+        mSpans = EmptyArray.OBJECT;
+        mSpanData = EmptyArray.INT;
 
         if (source instanceof Spanned) {
             Spanned sp = (Spanned) source;
@@ -115,9 +117,9 @@
         }
 
         if (mSpanCount + 1 >= mSpans.length) {
-            int newsize = ArrayUtils.idealIntArraySize(mSpanCount + 1);
-            Object[] newtags = new Object[newsize];
-            int[] newdata = new int[newsize * 3];
+            Object[] newtags = ArrayUtils.newUnpaddedObjectArray(
+                    GrowingArrayUtils.growSize(mSpanCount));
+            int[] newdata = new int[newtags.length * 3];
 
             System.arraycopy(mSpans, 0, newtags, 0, mSpanCount);
             System.arraycopy(mSpanData, 0, newdata, 0, mSpanCount * 3);
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index e7d6fda..535eee1 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -26,6 +26,7 @@
 import android.util.Log;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
 
 /**
  * StaticLayout is a Layout for text that will not be edited after it
@@ -130,9 +131,8 @@
             mEllipsizedWidth = outerwidth;
         }
 
-        mLines = new int[ArrayUtils.idealIntArraySize(2 * mColumns)];
-        mLineDirections = new Directions[
-                             ArrayUtils.idealIntArraySize(2 * mColumns)];
+        mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns);
+        mLines = new int[mLineDirections.length];
         mMaximumVisibleLineCount = maxLines;
 
         mMeasured = MeasuredText.obtain();
@@ -149,8 +149,8 @@
         super(text, null, 0, null, 0, 0);
 
         mColumns = COLUMNS_ELLIPSIZE;
-        mLines = new int[ArrayUtils.idealIntArraySize(2 * mColumns)];
-        mLineDirections = new Directions[ArrayUtils.idealIntArraySize(2 * mColumns)];
+        mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns);
+        mLines = new int[mLineDirections.length];
         // FIXME This is never recycled
         mMeasured = MeasuredText.obtain();
     }
@@ -215,8 +215,7 @@
                 if (chooseHt.length != 0) {
                     if (chooseHtv == null ||
                         chooseHtv.length < chooseHt.length) {
-                        chooseHtv = new int[ArrayUtils.idealIntArraySize(
-                                            chooseHt.length)];
+                        chooseHtv = ArrayUtils.newUnpaddedIntArray(chooseHt.length);
                     }
 
                     for (int i = 0; i < chooseHt.length; i++) {
@@ -599,16 +598,16 @@
         int[] lines = mLines;
 
         if (want >= lines.length) {
-            int nlen = ArrayUtils.idealIntArraySize(want + 1);
-            int[] grow = new int[nlen];
-            System.arraycopy(lines, 0, grow, 0, lines.length);
-            mLines = grow;
-            lines = grow;
-
-            Directions[] grow2 = new Directions[nlen];
+            Directions[] grow2 = ArrayUtils.newUnpaddedArray(
+                    Directions.class, GrowingArrayUtils.growSize(want));
             System.arraycopy(mLineDirections, 0, grow2, 0,
                              mLineDirections.length);
             mLineDirections = grow2;
+
+            int[] grow = new int[grow2.length];
+            System.arraycopy(lines, 0, grow, 0, lines.length);
+            mLines = grow;
+            lines = grow;
         }
 
         if (chooseHt != null) {
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 1fecf81..d892f19 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -153,7 +153,7 @@
 
         if (mCharsValid) {
             if (mChars == null || mChars.length < mLen) {
-                mChars = new char[ArrayUtils.idealCharArraySize(mLen)];
+                mChars = ArrayUtils.newUnpaddedCharArray(mLen);
             }
             TextUtils.getChars(text, start, limit, mChars, 0);
             if (hasReplacement) {
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 596ca8c..f06ae71 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1321,7 +1321,7 @@
         }
 
         if (buf == null || buf.length < len)
-            buf = new char[ArrayUtils.idealCharArraySize(len)];
+            buf = ArrayUtils.newUnpaddedCharArray(len);
 
         return buf;
     }
diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index df1d4cd..9a0b7fc 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -16,6 +16,8 @@
 
 package android.util;
 
+import libcore.util.EmptyArray;
+
 import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
@@ -234,8 +236,8 @@
      * will grow once items are added to it.
      */
     public ArrayMap() {
-        mHashes = ContainerHelpers.EMPTY_INTS;
-        mArray = ContainerHelpers.EMPTY_OBJECTS;
+        mHashes = EmptyArray.INT;
+        mArray = EmptyArray.OBJECT;
         mSize = 0;
     }
 
@@ -244,8 +246,8 @@
      */
     public ArrayMap(int capacity) {
         if (capacity == 0) {
-            mHashes = ContainerHelpers.EMPTY_INTS;
-            mArray = ContainerHelpers.EMPTY_OBJECTS;
+            mHashes = EmptyArray.INT;
+            mArray = EmptyArray.OBJECT;
         } else {
             allocArrays(capacity);
         }
@@ -253,8 +255,8 @@
     }
 
     private ArrayMap(boolean immutable) {
-        mHashes = EMPTY_IMMUTABLE_INTS;
-        mArray = ContainerHelpers.EMPTY_OBJECTS;
+        mHashes = EmptyArray.INT;
+        mArray = EmptyArray.OBJECT;
         mSize = 0;
     }
 
@@ -275,8 +277,8 @@
     public void clear() {
         if (mSize > 0) {
             freeArrays(mHashes, mArray, mSize);
-            mHashes = ContainerHelpers.EMPTY_INTS;
-            mArray = ContainerHelpers.EMPTY_OBJECTS;
+            mHashes = EmptyArray.INT;
+            mArray = EmptyArray.OBJECT;
             mSize = 0;
         }
     }
@@ -540,8 +542,8 @@
             // Now empty.
             if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to 0");
             freeArrays(mHashes, mArray, mSize);
-            mHashes = ContainerHelpers.EMPTY_INTS;
-            mArray = ContainerHelpers.EMPTY_OBJECTS;
+            mHashes = EmptyArray.INT;
+            mArray = EmptyArray.OBJECT;
             mSize = 0;
         } else {
             if (mHashes.length > (BASE_SIZE*2) && mSize < mHashes.length/3) {
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index 3c695e9..9d4b720 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -16,6 +16,8 @@
 
 package android.util;
 
+import libcore.util.EmptyArray;
+
 import java.lang.reflect.Array;
 import java.util.Collection;
 import java.util.Iterator;
@@ -222,8 +224,8 @@
      * will grow once items are added to it.
      */
     public ArraySet() {
-        mHashes = ContainerHelpers.EMPTY_INTS;
-        mArray = ContainerHelpers.EMPTY_OBJECTS;
+        mHashes = EmptyArray.INT;
+        mArray = EmptyArray.OBJECT;
         mSize = 0;
     }
 
@@ -232,8 +234,8 @@
      */
     public ArraySet(int capacity) {
         if (capacity == 0) {
-            mHashes = ContainerHelpers.EMPTY_INTS;
-            mArray = ContainerHelpers.EMPTY_OBJECTS;
+            mHashes = EmptyArray.INT;
+            mArray = EmptyArray.OBJECT;
         } else {
             allocArrays(capacity);
         }
@@ -258,8 +260,8 @@
     public void clear() {
         if (mSize != 0) {
             freeArrays(mHashes, mArray, mSize);
-            mHashes = ContainerHelpers.EMPTY_INTS;
-            mArray = ContainerHelpers.EMPTY_OBJECTS;
+            mHashes = EmptyArray.INT;
+            mArray = EmptyArray.OBJECT;
             mSize = 0;
         }
     }
@@ -413,8 +415,8 @@
             // Now empty.
             if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to 0");
             freeArrays(mHashes, mArray, mSize);
-            mHashes = ContainerHelpers.EMPTY_INTS;
-            mArray = ContainerHelpers.EMPTY_OBJECTS;
+            mHashes = EmptyArray.INT;
+            mArray = EmptyArray.OBJECT;
             mSize = 0;
         } else {
             if (mHashes.length > (BASE_SIZE*2) && mSize < mHashes.length/3) {
diff --git a/core/java/android/util/ContainerHelpers.java b/core/java/android/util/ContainerHelpers.java
index 624c4bd..4e5fefb 100644
--- a/core/java/android/util/ContainerHelpers.java
+++ b/core/java/android/util/ContainerHelpers.java
@@ -17,10 +17,6 @@
 package android.util;
 
 class ContainerHelpers {
-    static final boolean[] EMPTY_BOOLEANS = new boolean[0];
-    static final int[] EMPTY_INTS = new int[0];
-    static final long[] EMPTY_LONGS = new long[0];
-    static final Object[] EMPTY_OBJECTS = new Object[0];
 
     // This is Arrays.binarySearch(), but doesn't do any argument validation.
     static int binarySearch(int[] array, int size, int value) {
diff --git a/core/java/android/util/LongArray.java b/core/java/android/util/LongArray.java
index d5f15f0..54a6882 100644
--- a/core/java/android/util/LongArray.java
+++ b/core/java/android/util/LongArray.java
@@ -17,6 +17,7 @@
 package android.util;
 
 import com.android.internal.util.ArrayUtils;
+import libcore.util.EmptyArray;
 
 /**
  * Implements a growing array of long primitives.
@@ -41,10 +42,9 @@
      */
     public LongArray(int initialCapacity) {
         if (initialCapacity == 0) {
-            mValues = ContainerHelpers.EMPTY_LONGS;
+            mValues = EmptyArray.LONG;
         } else {
-            initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
-            mValues = new long[initialCapacity];
+            mValues = ArrayUtils.newUnpaddedLongArray(initialCapacity);
         }
         mSize = 0;
     }
@@ -97,7 +97,7 @@
             final int targetCap = currentSize + (currentSize < (MIN_CAPACITY_INCREMENT / 2) ?
                     MIN_CAPACITY_INCREMENT : currentSize >> 1);
             final int newCapacity = targetCap > minCapacity ? targetCap : minCapacity;
-            final long[] newValues = new long[ArrayUtils.idealLongArraySize(newCapacity)];
+            final long[] newValues = ArrayUtils.newUnpaddedLongArray(newCapacity);
             System.arraycopy(mValues, 0, newValues, 0, currentSize);
             mValues = newValues;
         }
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
index dab853a..6b45ff4 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -17,6 +17,9 @@
 package android.util;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
 
 /**
  * SparseArray mapping longs to Objects.  Unlike a normal array of Objects,
@@ -70,12 +73,11 @@
      */
     public LongSparseArray(int initialCapacity) {
         if (initialCapacity == 0) {
-            mKeys = ContainerHelpers.EMPTY_LONGS;
-            mValues = ContainerHelpers.EMPTY_OBJECTS;
+            mKeys = EmptyArray.LONG;
+            mValues = EmptyArray.OBJECT;
         } else {
-            initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
-            mKeys = new long[initialCapacity];
-            mValues = new Object[initialCapacity];
+            mKeys = ArrayUtils.newUnpaddedLongArray(initialCapacity);
+            mValues = ArrayUtils.newUnpaddedObjectArray(initialCapacity);
         }
         mSize = 0;
     }
@@ -202,28 +204,8 @@
                 i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
             }
 
-            if (mSize >= mKeys.length) {
-                int n = ArrayUtils.idealLongArraySize(mSize + 1);
-
-                long[] nkeys = new long[n];
-                Object[] nvalues = new Object[n];
-
-                // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
-                System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
-                System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
-                mKeys = nkeys;
-                mValues = nvalues;
-            }
-
-            if (mSize - i != 0) {
-                // Log.e("SparseArray", "move " + (mSize - i));
-                System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
-                System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
-            }
-
-            mKeys[i] = key;
-            mValues[i] = value;
+            mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
+            mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
             mSize++;
         }
     }
@@ -353,24 +335,9 @@
             gc();
         }
 
-        int pos = mSize;
-        if (pos >= mKeys.length) {
-            int n = ArrayUtils.idealLongArraySize(pos + 1);
-
-            long[] nkeys = new long[n];
-            Object[] nvalues = new Object[n];
-
-            // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
-            System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
-            System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
-            mKeys = nkeys;
-            mValues = nvalues;
-        }
-
-        mKeys[pos] = key;
-        mValues[pos] = value;
-        mSize = pos + 1;
+        mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
+        mValues = GrowingArrayUtils.append(mValues, mSize, value);
+        mSize++;
     }
 
     /**
diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java
index b8073dd..a361457 100644
--- a/core/java/android/util/LongSparseLongArray.java
+++ b/core/java/android/util/LongSparseLongArray.java
@@ -17,6 +17,9 @@
 package android.util;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
 
 /**
  * Map of {@code long} to {@code long}. Unlike a normal array of longs, there
@@ -62,12 +65,11 @@
      */
     public LongSparseLongArray(int initialCapacity) {
         if (initialCapacity == 0) {
-            mKeys = ContainerHelpers.EMPTY_LONGS;
-            mValues = ContainerHelpers.EMPTY_LONGS;
+            mKeys = EmptyArray.LONG;
+            mValues = EmptyArray.LONG;
         } else {
-            initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
-            mKeys = new long[initialCapacity];
-            mValues = new long[initialCapacity];
+            mKeys = ArrayUtils.newUnpaddedLongArray(initialCapacity);
+            mValues = new long[mKeys.length];
         }
         mSize = 0;
     }
@@ -140,17 +142,8 @@
         } else {
             i = ~i;
 
-            if (mSize >= mKeys.length) {
-                growKeyAndValueArrays(mSize + 1);
-            }
-
-            if (mSize - i != 0) {
-                System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
-                System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
-            }
-
-            mKeys[i] = key;
-            mValues[i] = value;
+            mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
+            mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
             mSize++;
         }
     }
@@ -234,27 +227,9 @@
             return;
         }
 
-        int pos = mSize;
-        if (pos >= mKeys.length) {
-            growKeyAndValueArrays(pos + 1);
-        }
-
-        mKeys[pos] = key;
-        mValues[pos] = value;
-        mSize = pos + 1;
-    }
-
-    private void growKeyAndValueArrays(int minNeededSize) {
-        int n = ArrayUtils.idealLongArraySize(minNeededSize);
-
-        long[] nkeys = new long[n];
-        long[] nvalues = new long[n];
-
-        System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
-        System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
-        mKeys = nkeys;
-        mValues = nvalues;
+        mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
+        mValues = GrowingArrayUtils.append(mValues, mSize, value);
+        mSize++;
     }
 
     /**
diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java
index 0f8da44..13cc88b 100644
--- a/core/java/android/util/Patterns.java
+++ b/core/java/android/util/Patterns.java
@@ -28,7 +28,12 @@
      *  List accurate as of 2011/07/18.  List taken from:
      *  http://data.iana.org/TLD/tlds-alpha-by-domain.txt
      *  This pattern is auto-generated by frameworks/ex/common/tools/make-iana-tld-pattern.py
+     *
+     *  @deprecated Due to the recent profileration of gTLDs, this API is
+     *  expected to become out-of-date very quickly. Therefore it is now
+     *  deprecated.
      */
+    @Deprecated
     public static final String TOP_LEVEL_DOMAIN_STR =
         "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
         + "|(biz|b[abdefghijmnorstvwyz])"
@@ -59,7 +64,9 @@
 
     /**
      *  Regular expression pattern to match all IANA top-level domains.
+     *  @deprecated This API is deprecated. See {@link #TOP_LEVEL_DOMAIN_STR}.
      */
+    @Deprecated
     public static final Pattern TOP_LEVEL_DOMAIN =
         Pattern.compile(TOP_LEVEL_DOMAIN_STR);
 
@@ -68,7 +75,10 @@
      *  List accurate as of 2011/07/18.  List taken from:
      *  http://data.iana.org/TLD/tlds-alpha-by-domain.txt
      *  This pattern is auto-generated by frameworks/ex/common/tools/make-iana-tld-pattern.py
+     *
+     *  @deprecated This API is deprecated. See {@link #TOP_LEVEL_DOMAIN_STR}.
      */
+    @Deprecated
     public static final String TOP_LEVEL_DOMAIN_STR_FOR_WEB_URL =
         "(?:"
         + "(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
@@ -107,6 +117,24 @@
     public static final String GOOD_IRI_CHAR =
         "a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
 
+    public static final Pattern IP_ADDRESS
+        = Pattern.compile(
+            "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]"
+            + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]"
+            + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
+            + "|[1-9][0-9]|[0-9]))");
+
+    /**
+     * RFC 1035 Section 2.3.4 limits the labels to a maximum 63 octets.
+     */
+    private static final String IRI
+        = "[" + GOOD_IRI_CHAR + "]([" + GOOD_IRI_CHAR + "\\-]{0,61}[" + GOOD_IRI_CHAR + "]){0,1}";
+
+    private static final String HOST_NAME = IRI + "(?:\\." + IRI + ")+";
+
+    public static final Pattern DOMAIN_NAME
+        = Pattern.compile("(" + HOST_NAME + "|" + IP_ADDRESS + ")");
+
     /**
      *  Regular expression pattern to match most part of RFC 3987
      *  Internationalized URLs, aka IRIs.  Commonly used Unicode characters are
@@ -116,13 +144,7 @@
         "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
         + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
         + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
-        + "((?:(?:[" + GOOD_IRI_CHAR + "][" + GOOD_IRI_CHAR + "\\-]{0,64}\\.)+"   // named host
-        + TOP_LEVEL_DOMAIN_STR_FOR_WEB_URL
-        + "|(?:(?:25[0-5]|2[0-4]" // or ip address
-        + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]"
-        + "|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1]"
-        + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
-        + "|[1-9][0-9]|[0-9])))"
+        + "(?:" + DOMAIN_NAME + ")"
         + "(?:\\:\\d{1,5})?)" // plus option port number
         + "(\\/(?:(?:[" + GOOD_IRI_CHAR + "\\;\\/\\?\\:\\@\\&\\=\\#\\~"  // plus option query params
         + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
@@ -130,19 +152,6 @@
                         // input.  This is to stop foo.sure from
                         // matching as foo.su
 
-    public static final Pattern IP_ADDRESS
-        = Pattern.compile(
-            "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]"
-            + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]"
-            + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
-            + "|[1-9][0-9]|[0-9]))");
-
-    public static final Pattern DOMAIN_NAME
-        = Pattern.compile(
-            "(((([" + GOOD_IRI_CHAR + "][" + GOOD_IRI_CHAR + "\\-]*)*[" + GOOD_IRI_CHAR + "]\\.)+"
-            + TOP_LEVEL_DOMAIN + ")|"
-            + IP_ADDRESS + ")");
-
     public static final Pattern EMAIL_ADDRESS
         = Pattern.compile(
             "[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}" +
@@ -159,7 +168,7 @@
      * might be phone numbers in arbitrary text, not for validating whether
      * something is in fact a phone number.  It will miss many things that
      * are legitimate phone numbers.
-     * 
+     *
      * <p> The pattern matches the following:
      * <ul>
      * <li>Optionally, a + sign followed immediately by one or more digits. Spaces, dots, or dashes
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index 46d9d45..92e874f 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -17,6 +17,9 @@
 package android.util;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
 
 /**
  * SparseArrays map integers to Objects.  Unlike a normal array of Objects,
@@ -70,12 +73,11 @@
      */
     public SparseArray(int initialCapacity) {
         if (initialCapacity == 0) {
-            mKeys = ContainerHelpers.EMPTY_INTS;
-            mValues = ContainerHelpers.EMPTY_OBJECTS;
+            mKeys = EmptyArray.INT;
+            mValues = EmptyArray.OBJECT;
         } else {
-            initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
-            mKeys = new int[initialCapacity];
-            mValues = new Object[initialCapacity];
+            mValues = ArrayUtils.newUnpaddedObjectArray(initialCapacity);
+            mKeys = new int[mValues.length];
         }
         mSize = 0;
     }
@@ -215,28 +217,8 @@
                 i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
             }
 
-            if (mSize >= mKeys.length) {
-                int n = ArrayUtils.idealIntArraySize(mSize + 1);
-
-                int[] nkeys = new int[n];
-                Object[] nvalues = new Object[n];
-
-                // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
-                System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
-                System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
-                mKeys = nkeys;
-                mValues = nvalues;
-            }
-
-            if (mSize - i != 0) {
-                // Log.e("SparseArray", "move " + (mSize - i));
-                System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
-                System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
-            }
-
-            mKeys[i] = key;
-            mValues[i] = value;
+            mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
+            mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
             mSize++;
         }
     }
@@ -368,24 +350,9 @@
             gc();
         }
 
-        int pos = mSize;
-        if (pos >= mKeys.length) {
-            int n = ArrayUtils.idealIntArraySize(pos + 1);
-
-            int[] nkeys = new int[n];
-            Object[] nvalues = new Object[n];
-
-            // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
-            System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
-            System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
-            mKeys = nkeys;
-            mValues = nvalues;
-        }
-
-        mKeys[pos] = key;
-        mValues[pos] = value;
-        mSize = pos + 1;
+        mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
+        mValues = GrowingArrayUtils.append(mValues, mSize, value);
+        mSize++;
     }
 
     /**
diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java
index f59ef0f6d..e293b1f 100644
--- a/core/java/android/util/SparseBooleanArray.java
+++ b/core/java/android/util/SparseBooleanArray.java
@@ -17,6 +17,9 @@
 package android.util;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
 
 /**
  * SparseBooleanArrays map integers to booleans.
@@ -57,12 +60,11 @@
      */
     public SparseBooleanArray(int initialCapacity) {
         if (initialCapacity == 0) {
-            mKeys = ContainerHelpers.EMPTY_INTS;
-            mValues = ContainerHelpers.EMPTY_BOOLEANS;
+            mKeys = EmptyArray.INT;
+            mValues = EmptyArray.BOOLEAN;
         } else {
-            initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
-            mKeys = new int[initialCapacity];
-            mValues = new boolean[initialCapacity];
+            mKeys = ArrayUtils.newUnpaddedIntArray(initialCapacity);
+            mValues = new boolean[mKeys.length];
         }
         mSize = 0;
     }
@@ -135,28 +137,8 @@
         } else {
             i = ~i;
 
-            if (mSize >= mKeys.length) {
-                int n = ArrayUtils.idealIntArraySize(mSize + 1);
-
-                int[] nkeys = new int[n];
-                boolean[] nvalues = new boolean[n];
-
-                // Log.e("SparseBooleanArray", "grow " + mKeys.length + " to " + n);
-                System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
-                System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
-                mKeys = nkeys;
-                mValues = nvalues;
-            }
-
-            if (mSize - i != 0) {
-                // Log.e("SparseBooleanArray", "move " + (mSize - i));
-                System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
-                System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
-            }
-
-            mKeys[i] = key;
-            mValues[i] = value;
+            mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
+            mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
             mSize++;
         }
     }
@@ -245,24 +227,9 @@
             return;
         }
 
-        int pos = mSize;
-        if (pos >= mKeys.length) {
-            int n = ArrayUtils.idealIntArraySize(pos + 1);
-
-            int[] nkeys = new int[n];
-            boolean[] nvalues = new boolean[n];
-
-            // Log.e("SparseBooleanArray", "grow " + mKeys.length + " to " + n);
-            System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
-            System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
-            mKeys = nkeys;
-            mValues = nvalues;
-        }
-
-        mKeys[pos] = key;
-        mValues[pos] = value;
-        mSize = pos + 1;
+        mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
+        mValues = GrowingArrayUtils.append(mValues, mSize, value);
+        mSize++;
     }
 
     /**
diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java
index 4f5ca07..2b85a21 100644
--- a/core/java/android/util/SparseIntArray.java
+++ b/core/java/android/util/SparseIntArray.java
@@ -17,6 +17,9 @@
 package android.util;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
 
 /**
  * SparseIntArrays map integers to integers.  Unlike a normal array of integers,
@@ -60,12 +63,11 @@
      */
     public SparseIntArray(int initialCapacity) {
         if (initialCapacity == 0) {
-            mKeys = ContainerHelpers.EMPTY_INTS;
-            mValues = ContainerHelpers.EMPTY_INTS;
+            mKeys = EmptyArray.INT;
+            mValues = EmptyArray.INT;
         } else {
-            initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
-            mKeys = new int[initialCapacity];
-            mValues = new int[initialCapacity];
+            mKeys = ArrayUtils.newUnpaddedIntArray(initialCapacity);
+            mValues = new int[mKeys.length];
         }
         mSize = 0;
     }
@@ -138,28 +140,8 @@
         } else {
             i = ~i;
 
-            if (mSize >= mKeys.length) {
-                int n = ArrayUtils.idealIntArraySize(mSize + 1);
-
-                int[] nkeys = new int[n];
-                int[] nvalues = new int[n];
-
-                // Log.e("SparseIntArray", "grow " + mKeys.length + " to " + n);
-                System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
-                System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
-                mKeys = nkeys;
-                mValues = nvalues;
-            }
-
-            if (mSize - i != 0) {
-                // Log.e("SparseIntArray", "move " + (mSize - i));
-                System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
-                System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
-            }
-
-            mKeys[i] = key;
-            mValues[i] = value;
+            mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
+            mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
             mSize++;
         }
     }
@@ -243,24 +225,9 @@
             return;
         }
 
-        int pos = mSize;
-        if (pos >= mKeys.length) {
-            int n = ArrayUtils.idealIntArraySize(pos + 1);
-
-            int[] nkeys = new int[n];
-            int[] nvalues = new int[n];
-
-            // Log.e("SparseIntArray", "grow " + mKeys.length + " to " + n);
-            System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
-            System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
-            mKeys = nkeys;
-            mValues = nvalues;
-        }
-
-        mKeys[pos] = key;
-        mValues[pos] = value;
-        mSize = pos + 1;
+        mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
+        mValues = GrowingArrayUtils.append(mValues, mSize, value);
+        mSize++;
     }
 
     /**
diff --git a/core/java/android/util/SparseLongArray.java b/core/java/android/util/SparseLongArray.java
index 39fc8a3..0166c4a 100644
--- a/core/java/android/util/SparseLongArray.java
+++ b/core/java/android/util/SparseLongArray.java
@@ -17,6 +17,9 @@
 package android.util;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
 
 /**
  * SparseLongArrays map integers to longs.  Unlike a normal array of longs,
@@ -60,12 +63,11 @@
      */
     public SparseLongArray(int initialCapacity) {
         if (initialCapacity == 0) {
-            mKeys = ContainerHelpers.EMPTY_INTS;
-            mValues = ContainerHelpers.EMPTY_LONGS;
+            mKeys = EmptyArray.INT;
+            mValues = EmptyArray.LONG;
         } else {
-            initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
-            mKeys = new int[initialCapacity];
-            mValues = new long[initialCapacity];
+            mValues = ArrayUtils.newUnpaddedLongArray(initialCapacity);
+            mKeys = new int[mValues.length];
         }
         mSize = 0;
     }
@@ -138,17 +140,8 @@
         } else {
             i = ~i;
 
-            if (mSize >= mKeys.length) {
-                growKeyAndValueArrays(mSize + 1);
-            }
-
-            if (mSize - i != 0) {
-                System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
-                System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
-            }
-
-            mKeys[i] = key;
-            mValues[i] = value;
+            mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
+            mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
             mSize++;
         }
     }
@@ -232,27 +225,9 @@
             return;
         }
 
-        int pos = mSize;
-        if (pos >= mKeys.length) {
-            growKeyAndValueArrays(pos + 1);
-        }
-
-        mKeys[pos] = key;
-        mValues[pos] = value;
-        mSize = pos + 1;
-    }
-
-    private void growKeyAndValueArrays(int minNeededSize) {
-        int n = ArrayUtils.idealLongArraySize(minNeededSize);
-
-        int[] nkeys = new int[n];
-        long[] nvalues = new long[n];
-
-        System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
-        System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
-        mKeys = nkeys;
-        mValues = nvalues;
+        mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
+        mValues = GrowingArrayUtils.append(mValues, mSize, value);
+        mSize++;
     }
 
     /**
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index abae068..477c994 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -52,7 +52,7 @@
  */
 final class AccessibilityInteractionController {
 
-    private static final boolean ENFORCE_NODE_TREE_CONSISTENT = Build.IS_DEBUGGABLE;
+    private static final boolean ENFORCE_NODE_TREE_CONSISTENT = false;
 
     private final ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList =
         new ArrayList<AccessibilityNodeInfo>();
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index 90824ab..d6e1781 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -555,6 +555,32 @@
     }
 
     @Override
+    public 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() {
@@ -1096,8 +1122,7 @@
             }
 
             if (checkRenderContext() != SURFACE_STATE_ERROR) {
-                int status = mCanvas.invokeFunctors(mRedrawClip);
-                handleFunctorStatus(attachInfo, status);
+                mCanvas.invokeFunctors(mRedrawClip);
             }
         }
     }
@@ -1203,7 +1228,7 @@
 
     private RenderNode buildDisplayList(View view, HardwareCanvas canvas) {
         if (mDrawDelta <= 0) {
-            return view.mDisplayList;
+            return view.mRenderNode;
         }
 
         view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
@@ -1214,12 +1239,12 @@
         canvas.clearLayerUpdates();
 
         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
-        RenderNode displayList = view.getDisplayList();
+        RenderNode renderNode = view.getDisplayList();
         Trace.traceEnd(Trace.TRACE_TAG_VIEW);
 
         endBuildDisplayListProfiling(buildDisplayListStartTime);
 
-        return displayList;
+        return renderNode;
     }
 
     private Rect beginFrame(HardwareCanvas canvas, Rect dirty, int surfaceState) {
@@ -1301,7 +1326,6 @@
             mProfileData[mProfileCurrentFrame + 1] = total;
         }
 
-        handleFunctorStatus(attachInfo, status);
         return status;
     }
 
@@ -1337,26 +1361,6 @@
         }
     }
 
-    private void handleFunctorStatus(View.AttachInfo attachInfo, int status) {
-        // If the draw flag is set, functors will be invoked while executing
-        // the tree of display lists
-        if ((status & RenderNode.STATUS_DRAW) != 0) {
-            if (mRedrawClip.isEmpty()) {
-                attachInfo.mViewRootImpl.invalidate();
-            } else {
-                attachInfo.mViewRootImpl.invalidateChildInParent(null, mRedrawClip);
-                mRedrawClip.setEmpty();
-            }
-        }
-
-        if ((status & RenderNode.STATUS_INVOKE) != 0 ||
-                attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) {
-            attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
-            mFunctorsRunnable.attachInfo = attachInfo;
-            attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY);
-        }
-    }
-
     @Override
     void detachFunctor(long functor) {
         if (mCanvas != null) {
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index f695b20..233f846 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -23,7 +23,7 @@
 
 /**
  * Hardware accelerated canvas.
- * 
+ *
  * @hide
  */
 public abstract class HardwareCanvas extends Canvas {
@@ -40,7 +40,7 @@
 
     /**
      * Invoked before any drawing operation is performed in this canvas.
-     * 
+     *
      * @param dirty The dirty rectangle to update, can be null.
      * @return {@link RenderNode#STATUS_DREW} if anything was drawn (such as a call to clear
      *         the canvas).
@@ -70,13 +70,11 @@
      * Draws the specified display list onto this canvas.
      *
      * @param displayList The display list to replay.
-     * @param dirty The dirty region to redraw in the next pass, matters only
-     *        if this method returns {@link RenderNode#STATUS_DRAW}, can be null.
+     * @param dirty Ignored, can be null.
      * @param flags Optional flags about drawing, see {@link RenderNode} for
      *              the possible flags.
      *
-     * @return One of {@link RenderNode#STATUS_DONE}, {@link RenderNode#STATUS_DRAW}, or
-     *         {@link RenderNode#STATUS_INVOKE}, or'd with {@link RenderNode#STATUS_DREW}
+     * @return One of {@link RenderNode#STATUS_DONE} or {@link RenderNode#STATUS_DREW}
      *         if anything was drawn.
      *
      * @hide
@@ -101,9 +99,8 @@
      * This function may return true if an invalidation is needed after the call.
      *
      * @param drawGLFunction A native function pointer
-     *                       
-     * @return One of {@link RenderNode#STATUS_DONE}, {@link RenderNode#STATUS_DRAW} or
-     *         {@link RenderNode#STATUS_INVOKE}
+     *
+     * @return {@link RenderNode#STATUS_DONE}
      *
      * @hide
      */
@@ -114,11 +111,10 @@
 
     /**
      * Invoke all the functors who requested to be invoked during the previous frame.
-     * 
-     * @param dirty The region to redraw when the functors return {@link RenderNode#STATUS_DRAW}
-     *              
-     * @return One of {@link RenderNode#STATUS_DONE}, {@link RenderNode#STATUS_DRAW} or
-     *         {@link RenderNode#STATUS_INVOKE}
+     *
+     * @param dirty Ignored
+     *
+     * @return Ignored
      *
      * @hide
      */
@@ -154,7 +150,7 @@
 
     /**
      * Indicates that the specified layer must be updated as soon as possible.
-     * 
+     *
      * @param layer The layer to update
      *
      * @see #clearLayerUpdates()
@@ -187,7 +183,7 @@
 
     /**
      * Removes all enqueued layer updates.
-     * 
+     *
      * @see #pushLayerUpdate(HardwareLayer)
      *
      * @hide
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 34efcf5..4f646e1 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -438,6 +438,17 @@
     abstract void attachFunctor(View.AttachInfo attachInfo, long functor);
 
     /**
+     * Schedules the functor for execution in either kModeProcess or
+     * kModeProcessNoContext, depending on whether or not there is an EGLContext.
+     *
+     * @param functor The native functor to invoke
+     * @param waitForCompletion If true, this will not return until the functor
+     *                          has invoked. If false, the functor may be invoked
+     *                          asynchronously.
+     */
+    public abstract void invokeFunctor(long functor, boolean waitForCompletion);
+
+    /**
      * Initializes the hardware renderer for the specified surface and setup the
      * renderer for drawing, if needed. This is invoked when the ViewAncestor has
      * potentially lost the hardware renderer. The hardware renderer should be
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 0b12cbe..ae5f37e 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -579,6 +579,18 @@
     }
 
     /**
+     * Determines whether the input device supports the given source or sources.
+     *
+     * @param source The input source or sources to check against. This can be a generic device
+     * type such as {@link InputDevice#SOURCE_MOUSE}, a more generic device class, such as
+     * {@link InputDevice#SOURCE_CLASS_POINTER}, or a combination of sources bitwise ORed together.
+     * @return Whether the device can produce all of the given sources.
+     */
+    public boolean supportsSource(int source) {
+        return (mSources & source) == source;
+    }
+
+    /**
      * Gets the keyboard type.
      * @return The keyboard type.
      */
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index c4fac46..e19bda9 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -590,6 +590,7 @@
             Object[] args = mConstructorArgs;
             args[1] = attrs;
 
+            constructor.setAccessible(true);
             final View view = constructor.newInstance(args);
             if (view instanceof ViewStub) {
                 // always use ourselves when inflating ViewStub later
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 6c8c3c7..a27c313 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -269,8 +269,8 @@
     }
 
     /**
-     * Returns whether the display list is currently usable. If this returns false,
-     * the display list should be re-recorded prior to replaying it.
+     * Returns whether the RenderNode's display list content is currently usable.
+     * If this returns false, the display list should be re-recorded prior to replaying it.
      *
      * @return boolean true if the display list is able to be replayed, false otherwise.
      */
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 2a488a0..7b8a1ff 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -186,6 +186,11 @@
     }
 
     @Override
+    public void invokeFunctor(long functor, boolean waitForCompletion) {
+        nInvokeFunctor(mNativeProxy, functor, waitForCompletion);
+    }
+
+    @Override
     HardwareLayer createDisplayListLayer(int width, int height) {
         long layer = nCreateDisplayListLayer(mNativeProxy, width, height);
         return HardwareLayer.adoptDisplayListLayer(this, layer);
@@ -266,6 +271,7 @@
 
     private static native void nAttachFunctor(long nativeProxy, long functor);
     private static native void nDetachFunctor(long nativeProxy, long functor);
+    private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion);
 
     private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
     private static native long nCreateTextureLayer(long nativeProxy);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f2b9b96..5be4698 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import android.animation.RevealAnimator;
+import android.animation.ValueAnimator;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -3549,13 +3551,13 @@
     private Bitmap mUnscaledDrawingCache;
 
     /**
-     * Display list used for the View content.
+     * RenderNode holding View properties, potentially holding a DisplayList of View content.
      * <p>
      * When non-null and valid, this is expected to contain an up-to-date copy
-     * of the View content. It is cleared on temporary detach and reset on
+     * of the View content. Its DisplayList content is cleared on temporary detach and reset on
      * cleanup.
      */
-    RenderNode mDisplayList;
+    RenderNode mRenderNode;
 
     /**
      * Set to true when the view is sending hover accessibility events because it
@@ -9016,10 +9018,13 @@
      * @return True if the event was handled, false otherwise.
      */
     public boolean onTouchEvent(MotionEvent event) {
+        final float x = event.getX();
+        final float y = event.getY();
         final int viewFlags = mViewFlags;
 
         if ((viewFlags & ENABLED_MASK) == DISABLED) {
             if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
+                clearHotspot(R.attr.state_pressed);
                 setPressed(false);
             }
             // A disabled view that is clickable still consumes the touch
@@ -9052,6 +9057,7 @@
                             // showed it as pressed.  Make it show the pressed
                             // state now (before scheduling the click) to ensure
                             // the user sees it.
+                            setHotspot(R.attr.state_pressed, x, y);
                             setPressed(true);
                        }
 
@@ -9084,6 +9090,7 @@
                             // If the post failed, unpress right now
                             mUnsetPressedState.run();
                         }
+
                         removeTapCallback();
                     }
                     break;
@@ -9105,23 +9112,26 @@
                         if (mPendingCheckForTap == null) {
                             mPendingCheckForTap = new CheckForTap();
                         }
+                        mPendingCheckForTap.x = event.getX();
+                        mPendingCheckForTap.y = event.getY();
                         postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                     } else {
                         // Not inside a scrolling container, so show the feedback right away
+                        setHotspot(R.attr.state_pressed, x, y);
                         setPressed(true);
                         checkForLongClick(0);
                     }
                     break;
 
                 case MotionEvent.ACTION_CANCEL:
+                    clearHotspot(R.attr.state_pressed);
                     setPressed(false);
                     removeTapCallback();
                     removeLongPressCallback();
                     break;
 
                 case MotionEvent.ACTION_MOVE:
-                    final int x = (int) event.getX();
-                    final int y = (int) event.getY();
+                    setHotspot(R.attr.state_pressed, x, y);
 
                     // Be lenient about moving outside of buttons
                     if (!pointInView(x, y, mTouchSlop)) {
@@ -9137,46 +9147,24 @@
                     break;
             }
 
-            if (mBackground != null && mBackground.supportsHotspots()) {
-                manageTouchHotspot(event);
-            }
-
             return true;
         }
 
         return false;
     }
 
-    private void manageTouchHotspot(MotionEvent event) {
-        switch (event.getAction()) {
-            case MotionEvent.ACTION_DOWN:
-            case MotionEvent.ACTION_POINTER_DOWN: {
-                final int index = event.getActionIndex();
-                setPointerHotspot(event, index);
-            } break;
-            case MotionEvent.ACTION_MOVE: {
-                final int count = event.getPointerCount();
-                for (int index = 0; index < count; index++) {
-                    setPointerHotspot(event, index);
-                }
-            } break;
-            case MotionEvent.ACTION_POINTER_UP: {
-                final int actionIndex = event.getActionIndex();
-                final int pointerId = event.getPointerId(actionIndex);
-                mBackground.removeHotspot(pointerId);
-            } break;
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                mBackground.clearHotspots();
-                break;
+    private void setHotspot(int id, float x, float y) {
+        final Drawable bg = mBackground;
+        if (bg != null && bg.supportsHotspots()) {
+            bg.setHotspot(id, x, y);
         }
     }
 
-    private void setPointerHotspot(MotionEvent event, int index) {
-        final int id = event.getPointerId(index);
-        final float x = event.getX(index);
-        final float y = event.getY(index);
-        mBackground.setHotspot(id, x, y);
+    private void clearHotspot(int id) {
+        final Drawable bg = mBackground;
+        if (bg != null && bg.supportsHotspots()) {
+            bg.removeHotspot(id);
+        }
     }
 
     /**
@@ -9731,6 +9719,12 @@
         }
     }
 
+    void ensureRenderNode() {
+        if (mRenderNode == null) {
+            mRenderNode = RenderNode.create(getClass().getName());
+        }
+    }
+
     /**
      * Recomputes the transform matrix if necessary.
      */
@@ -9873,8 +9867,8 @@
         info.mMatrixDirty = true;
 
         invalidateViewProperty(false, false);
-        if (mDisplayList != null) {
-            mDisplayList.setCameraDistance(-Math.abs(distance) / dpi);
+        if (mRenderNode != null) {
+            mRenderNode.setCameraDistance(-Math.abs(distance) / dpi);
         }
         if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
             // View was rejected last time it was drawn by its parent; this may have changed
@@ -9919,8 +9913,8 @@
             info.mRotation = rotation;
             info.mMatrixDirty = true;
             invalidateViewProperty(false, true);
-            if (mDisplayList != null) {
-                mDisplayList.setRotation(rotation);
+            if (mRenderNode != null) {
+                mRenderNode.setRotation(rotation);
             }
             if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
@@ -9970,8 +9964,8 @@
             info.mRotationY = rotationY;
             info.mMatrixDirty = true;
             invalidateViewProperty(false, true);
-            if (mDisplayList != null) {
-                mDisplayList.setRotationY(rotationY);
+            if (mRenderNode != null) {
+                mRenderNode.setRotationY(rotationY);
             }
             if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
@@ -10021,8 +10015,8 @@
             info.mRotationX = rotationX;
             info.mMatrixDirty = true;
             invalidateViewProperty(false, true);
-            if (mDisplayList != null) {
-                mDisplayList.setRotationX(rotationX);
+            if (mRenderNode != null) {
+                mRenderNode.setRotationX(rotationX);
             }
             if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
@@ -10064,8 +10058,8 @@
             info.mScaleX = scaleX;
             info.mMatrixDirty = true;
             invalidateViewProperty(false, true);
-            if (mDisplayList != null) {
-                mDisplayList.setScaleX(scaleX);
+            if (mRenderNode != null) {
+                mRenderNode.setScaleX(scaleX);
             }
             if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
@@ -10107,8 +10101,8 @@
             info.mScaleY = scaleY;
             info.mMatrixDirty = true;
             invalidateViewProperty(false, true);
-            if (mDisplayList != null) {
-                mDisplayList.setScaleY(scaleY);
+            if (mRenderNode != null) {
+                mRenderNode.setScaleY(scaleY);
             }
             if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
@@ -10160,8 +10154,8 @@
             info.mPivotX = pivotX;
             info.mMatrixDirty = true;
             invalidateViewProperty(false, true);
-            if (mDisplayList != null) {
-                mDisplayList.setPivotX(pivotX);
+            if (mRenderNode != null) {
+                mRenderNode.setPivotX(pivotX);
             }
             if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
@@ -10212,8 +10206,8 @@
             info.mPivotY = pivotY;
             info.mMatrixDirty = true;
             invalidateViewProperty(false, true);
-            if (mDisplayList != null) {
-                mDisplayList.setPivotY(pivotY);
+            if (mRenderNode != null) {
+                mRenderNode.setPivotY(pivotY);
             }
             if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
@@ -10296,8 +10290,8 @@
             } else {
                 mPrivateFlags &= ~PFLAG_ALPHA_SET;
                 invalidateViewProperty(true, false);
-                if (mDisplayList != null) {
-                    mDisplayList.setAlpha(getFinalAlpha());
+                if (mRenderNode != null) {
+                    mRenderNode.setAlpha(getFinalAlpha());
                 }
             }
         }
@@ -10323,8 +10317,8 @@
                 return true;
             } else {
                 mPrivateFlags &= ~PFLAG_ALPHA_SET;
-                if (mDisplayList != null) {
-                    mDisplayList.setAlpha(getFinalAlpha());
+                if (mRenderNode != null) {
+                    mRenderNode.setAlpha(getFinalAlpha());
                 }
             }
         }
@@ -10346,8 +10340,8 @@
             mTransformationInfo.mTransitionAlpha = alpha;
             mPrivateFlags &= ~PFLAG_ALPHA_SET;
             invalidateViewProperty(true, false);
-            if (mDisplayList != null) {
-                mDisplayList.setAlpha(getFinalAlpha());
+            if (mRenderNode != null) {
+                mRenderNode.setAlpha(getFinalAlpha());
             }
         }
     }
@@ -10420,8 +10414,8 @@
             int oldHeight = mBottom - mTop;
 
             mTop = top;
-            if (mDisplayList != null) {
-                mDisplayList.setTop(mTop);
+            if (mRenderNode != null) {
+                mRenderNode.setTop(mTop);
             }
 
             sizeChange(width, mBottom - mTop, width, oldHeight);
@@ -10493,8 +10487,8 @@
             int oldHeight = mBottom - mTop;
 
             mBottom = bottom;
-            if (mDisplayList != null) {
-                mDisplayList.setBottom(mBottom);
+            if (mRenderNode != null) {
+                mRenderNode.setBottom(mBottom);
             }
 
             sizeChange(width, mBottom - mTop, width, oldHeight);
@@ -10560,8 +10554,8 @@
             int height = mBottom - mTop;
 
             mLeft = left;
-            if (mDisplayList != null) {
-                mDisplayList.setLeft(left);
+            if (mRenderNode != null) {
+                mRenderNode.setLeft(left);
             }
 
             sizeChange(mRight - mLeft, height, oldWidth, height);
@@ -10624,8 +10618,8 @@
             int height = mBottom - mTop;
 
             mRight = right;
-            if (mDisplayList != null) {
-                mDisplayList.setRight(mRight);
+            if (mRenderNode != null) {
+                mRenderNode.setRight(mRight);
             }
 
             sizeChange(mRight - mLeft, height, oldWidth, height);
@@ -10725,8 +10719,8 @@
             info.mTranslationX = translationX;
             info.mMatrixDirty = true;
             invalidateViewProperty(false, true);
-            if (mDisplayList != null) {
-                mDisplayList.setTranslationX(translationX);
+            if (mRenderNode != null) {
+                mRenderNode.setTranslationX(translationX);
             }
             if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
@@ -10766,8 +10760,8 @@
             info.mTranslationY = translationY;
             info.mMatrixDirty = true;
             invalidateViewProperty(false, true);
-            if (mDisplayList != null) {
-                mDisplayList.setTranslationY(translationY);
+            if (mRenderNode != null) {
+                mRenderNode.setTranslationY(translationY);
             }
             if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
@@ -10799,8 +10793,8 @@
             info.mTranslationZ = translationZ;
             info.mMatrixDirty = true;
             invalidateViewProperty(false, true);
-            if (mDisplayList != null) {
-                mDisplayList.setTranslationZ(translationZ);
+            if (mRenderNode != null) {
+                mRenderNode.setTranslationZ(translationZ);
             }
             if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
@@ -10810,6 +10804,43 @@
     }
 
     /**
+     * Returns a ValueAnimator which can animate a clipping circle.
+     * <p>
+     * The View will be clipped to the animating circle.
+     * <p>
+     * Any shadow cast by the View will respect the circular clip from this animator.
+     *
+     * @param centerX The x coordinate of the center of the animating circle.
+     * @param centerY The y coordinate of the center of the animating circle.
+     * @param startRadius The starting radius of the animating circle.
+     * @param endRadius The ending radius of the animating circle.
+     */
+    public final ValueAnimator createRevealAnimator(int centerX,  int centerY,
+            float startRadius, float endRadius) {
+        return RevealAnimator.ofRevealCircle(this, centerX, centerY,
+                startRadius, endRadius, false);
+    }
+
+    /**
+     * Returns a ValueAnimator which can animate a clearing circle.
+     * <p>
+     * The View is prevented from drawing within the circle, so the content
+     * behind the View shows through.
+     *
+     * @param centerX The x coordinate of the center of the animating circle.
+     * @param centerY The y coordinate of the center of the animating circle.
+     * @param startRadius The starting radius of the animating circle.
+     * @param endRadius The ending radius of the animating circle.
+     *
+     * @hide
+     */
+    public final ValueAnimator createClearCircleAnimator(int centerX,  int centerY,
+            float startRadius, float endRadius) {
+        return RevealAnimator.ofRevealCircle(this, centerX, centerY,
+                startRadius, endRadius, true);
+    }
+
+    /**
      * Sets the outline of the view, which defines the shape of the shadow it
      * casts, and can used for clipping.
      * <p>
@@ -10839,8 +10870,8 @@
             mOutline.set(outline);
         }
 
-        if (mDisplayList != null) {
-            mDisplayList.setOutline(mOutline);
+        if (mRenderNode != null) {
+            mRenderNode.setOutline(mOutline);
         }
     }
 
@@ -10876,8 +10907,8 @@
             } else {
                 mPrivateFlags3 &= ~PFLAG3_CLIP_TO_OUTLINE;
             }
-            if (mDisplayList != null) {
-                mDisplayList.setClipToOutline(clipToOutline);
+            if (mRenderNode != null) {
+                mRenderNode.setClipToOutline(clipToOutline);
             }
         }
     }
@@ -10889,8 +10920,10 @@
      */
     public void setRevealClip(boolean shouldClip, boolean inverseClip,
             float x, float y, float radius) {
-        if (mDisplayList != null) {
-            mDisplayList.setRevealClip(shouldClip, inverseClip, x, y, radius);
+        if (mRenderNode != null) {
+            mRenderNode.setRevealClip(shouldClip, inverseClip, x, y, radius);
+            // TODO: Handle this invalidate in a better way, or purely in native.
+            invalidate();
         }
     }
 
@@ -11000,7 +11033,7 @@
             final boolean matrixIsIdentity = mTransformationInfo == null
                     || mTransformationInfo.mMatrixIsIdentity;
             if (matrixIsIdentity) {
-                if (mDisplayList != null) {
+                if (mRenderNode != null) {
                     invalidateViewProperty(false, false);
                 } else {
                     final ViewParent p = mParent;
@@ -11028,8 +11061,8 @@
 
             mTop += offset;
             mBottom += offset;
-            if (mDisplayList != null) {
-                mDisplayList.offsetTopAndBottom(offset);
+            if (mRenderNode != null) {
+                mRenderNode.offsetTopAndBottom(offset);
                 invalidateViewProperty(false, false);
             } else {
                 if (!matrixIsIdentity) {
@@ -11051,7 +11084,7 @@
             final boolean matrixIsIdentity = mTransformationInfo == null
                     || mTransformationInfo.mMatrixIsIdentity;
             if (matrixIsIdentity) {
-                if (mDisplayList != null) {
+                if (mRenderNode != null) {
                     invalidateViewProperty(false, false);
                 } else {
                     final ViewParent p = mParent;
@@ -11076,8 +11109,8 @@
 
             mLeft += offset;
             mRight += offset;
-            if (mDisplayList != null) {
-                mDisplayList.offsetLeftAndRight(offset);
+            if (mRenderNode != null) {
+                mRenderNode.offsetLeftAndRight(offset);
                 invalidateViewProperty(false, false);
             } else {
                 if (!matrixIsIdentity) {
@@ -11520,7 +11553,7 @@
      * list properties are not being used in this view
      */
     void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) {
-        if (mDisplayList == null || (mPrivateFlags & PFLAG_DRAW_ANIMATION) == PFLAG_DRAW_ANIMATION) {
+        if (mRenderNode == null || (mPrivateFlags & PFLAG_DRAW_ANIMATION) == PFLAG_DRAW_ANIMATION) {
             if (invalidateParent) {
                 invalidateParentCaches();
             }
@@ -13687,10 +13720,7 @@
 
             mHardwareLayer.setLayerPaint(mLayerPaint);
             RenderNode displayList = mHardwareLayer.startRecording();
-            if (getDisplayList(displayList, true) != displayList) {
-                throw new IllegalStateException("getDisplayList() didn't return"
-                        + " the input displaylist for a hardware layer!");
-            }
+            updateDisplayListIfDirty(displayList, true);
             mHardwareLayer.endRecording(mLocalDirtyRect);
             mLocalDirtyRect.setEmpty();
         }
@@ -13831,29 +13861,34 @@
      * Otherwise, the same display list will be returned (after having been rendered into
      * along the way, depending on the invalidation state of the view).
      *
-     * @param displayList The previous version of this displayList, could be null.
+     * @param renderNode The previous version of this displayList, could be null.
      * @param isLayer Whether the requester of the display list is a layer. If so,
      * the view will avoid creating a layer inside the resulting display list.
      * @return A new or reused DisplayList object.
      */
-    private RenderNode getDisplayList(RenderNode displayList, boolean isLayer) {
+    private void updateDisplayListIfDirty(@NonNull RenderNode renderNode, boolean isLayer) {
         final HardwareRenderer renderer = getHardwareRenderer();
+        if (renderNode == null) {
+            throw new IllegalArgumentException("RenderNode must not be null");
+        }
         if (renderer == null || !canHaveDisplayList()) {
-            return null;
+            // can't populate RenderNode, don't try
+            return;
         }
 
-        if (((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 ||
-                displayList == null || !displayList.isValid() ||
-                (!isLayer && mRecreateDisplayList))) {
+        if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0
+                || !renderNode.isValid()
+                || (!isLayer && mRecreateDisplayList)) {
             // Don't need to recreate the display list, just need to tell our
             // children to restore/recreate theirs
-            if (displayList != null && displayList.isValid() &&
-                    !isLayer && !mRecreateDisplayList) {
+            if (renderNode.isValid()
+                    && !isLayer
+                    && !mRecreateDisplayList) {
                 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
                 mPrivateFlags &= ~PFLAG_DIRTY_MASK;
                 dispatchGetDisplayList();
 
-                return displayList;
+                return; // no work needed
             }
 
             if (!isLayer) {
@@ -13861,20 +13896,13 @@
                 // we copy in child display lists into ours in drawChild()
                 mRecreateDisplayList = true;
             }
-            if (displayList == null) {
-                displayList = RenderNode.create(getClass().getName());
-                // If we're creating a new display list, make sure our parent gets invalidated
-                // since they will need to recreate their display list to account for this
-                // new child display list.
-                invalidateParentCaches();
-            }
 
             boolean caching = false;
             int width = mRight - mLeft;
             int height = mBottom - mTop;
             int layerType = getLayerType();
 
-            final HardwareCanvas canvas = displayList.start(width, height);
+            final HardwareCanvas canvas = renderNode.start(width, height);
 
             try {
                 if (!isLayer && layerType != LAYER_TYPE_NONE) {
@@ -13917,12 +13945,12 @@
                     }
                 }
             } finally {
-                displayList.end(renderer, canvas);
-                displayList.setCaching(caching);
+                renderNode.end(renderer, canvas);
+                renderNode.setCaching(caching);
                 if (isLayer) {
-                    displayList.setLeftTopRightBottom(0, 0, width, height);
+                    renderNode.setLeftTopRightBottom(0, 0, width, height);
                 } else {
-                    setDisplayListProperties(displayList);
+                    setDisplayListProperties(renderNode);
                 }
 
                 if (renderer != getHardwareRenderer()) {
@@ -13937,26 +13965,25 @@
             mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
             mPrivateFlags &= ~PFLAG_DIRTY_MASK;
         }
-
-        return displayList;
     }
 
     /**
-     * <p>Returns a display list that can be used to draw this view again
-     * without executing its draw method.</p>
+     * Returns a RenderNode with View draw content recorded, which can be
+     * used to draw this view again without executing its draw method.
      *
-     * @return A DisplayList ready to replay, or null if caching is not enabled.
+     * @return A RenderNode ready to replay, or null if caching is not enabled.
      *
      * @hide
      */
     public RenderNode getDisplayList() {
-        mDisplayList = getDisplayList(mDisplayList, false);
-        return mDisplayList;
+        ensureRenderNode();
+        updateDisplayListIfDirty(mRenderNode, false);
+        return mRenderNode;
     }
 
     private void resetDisplayList() {
-        if (mDisplayList != null && mDisplayList.isValid()) {
-            mDisplayList.destroyDisplayListData();
+        if (mRenderNode != null && mRenderNode.isValid()) {
+            mRenderNode.destroyDisplayListData();
         }
 
         if (mBackgroundDisplayList != null && mBackgroundDisplayList.isValid()) {
@@ -14654,9 +14681,9 @@
             transformToApply = parent.getChildTransformation();
         } else {
             if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) ==
-                    PFLAG3_VIEW_IS_ANIMATING_TRANSFORM && mDisplayList != null) {
+                    PFLAG3_VIEW_IS_ANIMATING_TRANSFORM && mRenderNode != null) {
                 // No longer animating: clear out old animation matrix
-                mDisplayList.setAnimationMatrix(null);
+                mRenderNode.setAnimationMatrix(null);
                 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
             }
             if (!useDisplayListProperties &&
@@ -15169,8 +15196,8 @@
             if ((mPrivateFlags3 & PFLAG3_OUTLINE_DEFINED) == 0) {
                 // Outline not currently define, query from background
                 mOutline = background.getOutline();
-                if (mDisplayList != null) {
-                    mDisplayList.setOutline(mOutline);
+                if (mRenderNode != null) {
+                    mRenderNode.setOutline(mOutline);
                 }
             }
         }
@@ -15506,8 +15533,8 @@
             mTop = top;
             mRight = right;
             mBottom = bottom;
-            if (mDisplayList != null) {
-                mDisplayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
+            if (mRenderNode != null) {
+                mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
             }
 
             mPrivateFlags |= PFLAG_HAS_BOUNDS;
@@ -19093,10 +19120,10 @@
         }
     }
 
-    class CheckForLongPress implements Runnable {
-
+    private final class CheckForLongPress implements Runnable {
         private int mOriginalWindowAttachCount;
 
+        @Override
         public void run() {
             if (isPressed() && (mParent != null)
                     && mOriginalWindowAttachCount == mWindowAttachCount) {
@@ -19112,14 +19139,20 @@
     }
 
     private final class CheckForTap implements Runnable {
+        public float x;
+        public float y;
+
+        @Override
         public void run() {
             mPrivateFlags &= ~PFLAG_PREPRESSED;
+            setHotspot(R.attr.state_pressed, x, y);
             setPressed(true);
             checkForLongClick(ViewConfiguration.getTapTimeout());
         }
     }
 
     private final class PerformClick implements Runnable {
+        @Override
         public void run() {
             performClick();
         }
@@ -19398,7 +19431,9 @@
     }
 
     private final class UnsetPressedState implements Runnable {
+        @Override
         public void run() {
+            clearHotspot(R.attr.state_pressed);
             setPressed(false);
         }
     }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index aadaa7f..bcc82fb 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -31,7 +31,6 @@
 import android.graphics.RectF;
 import android.graphics.Region;
 import android.os.Build;
-import android.os.Bundle;
 import android.os.Parcelable;
 import android.os.SystemClock;
 import android.util.AttributeSet;
@@ -3174,8 +3173,8 @@
             setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
             for (int i = 0; i < mChildrenCount; ++i) {
                 View child = getChildAt(i);
-                if (child.mDisplayList != null) {
-                    child.mDisplayList.setClipToBounds(clipChildren);
+                if (child.mRenderNode != null) {
+                    child.mRenderNode.setClipToBounds(clipChildren);
                 }
             }
         }
@@ -4610,9 +4609,9 @@
             final View v = children[i];
             v.mTop += offset;
             v.mBottom += offset;
-            if (v.mDisplayList != null) {
+            if (v.mRenderNode != null) {
                 invalidate = true;
-                v.mDisplayList.offsetTopAndBottom(offset);
+                v.mRenderNode.offsetTopAndBottom(offset);
             }
         }
 
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 563ffb7..bbae0ca 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -925,51 +925,51 @@
      */
     private void setValue(int propertyConstant, float value) {
         final View.TransformationInfo info = mView.mTransformationInfo;
-        final RenderNode displayList = mView.mDisplayList;
+        final RenderNode renderNode = mView.mRenderNode;
         switch (propertyConstant) {
             case TRANSLATION_X:
                 info.mTranslationX = value;
-                if (displayList != null) displayList.setTranslationX(value);
+                if (renderNode != null) renderNode.setTranslationX(value);
                 break;
             case TRANSLATION_Y:
                 info.mTranslationY = value;
-                if (displayList != null) displayList.setTranslationY(value);
+                if (renderNode != null) renderNode.setTranslationY(value);
                 break;
             case TRANSLATION_Z:
                 info.mTranslationZ = value;
-                if (displayList != null) displayList.setTranslationZ(value);
+                if (renderNode != null) renderNode.setTranslationZ(value);
                 break;
             case ROTATION:
                 info.mRotation = value;
-                if (displayList != null) displayList.setRotation(value);
+                if (renderNode != null) renderNode.setRotation(value);
                 break;
             case ROTATION_X:
                 info.mRotationX = value;
-                if (displayList != null) displayList.setRotationX(value);
+                if (renderNode != null) renderNode.setRotationX(value);
                 break;
             case ROTATION_Y:
                 info.mRotationY = value;
-                if (displayList != null) displayList.setRotationY(value);
+                if (renderNode != null) renderNode.setRotationY(value);
                 break;
             case SCALE_X:
                 info.mScaleX = value;
-                if (displayList != null) displayList.setScaleX(value);
+                if (renderNode != null) renderNode.setScaleX(value);
                 break;
             case SCALE_Y:
                 info.mScaleY = value;
-                if (displayList != null) displayList.setScaleY(value);
+                if (renderNode != null) renderNode.setScaleY(value);
                 break;
             case X:
                 info.mTranslationX = value - mView.mLeft;
-                if (displayList != null) displayList.setTranslationX(value - mView.mLeft);
+                if (renderNode != null) renderNode.setTranslationX(value - mView.mLeft);
                 break;
             case Y:
                 info.mTranslationY = value - mView.mTop;
-                if (displayList != null) displayList.setTranslationY(value - mView.mTop);
+                if (renderNode != null) renderNode.setTranslationY(value - mView.mTop);
                 break;
             case ALPHA:
                 info.mAlpha = value;
-                if (displayList != null) displayList.setAlpha(value);
+                if (renderNode != null) renderNode.setAlpha(value);
                 break;
         }
     }
@@ -1093,7 +1093,7 @@
                 // Shouldn't happen, but just to play it safe
                 return;
             }
-            boolean useDisplayListProperties = mView.mDisplayList != null;
+            boolean useRenderNodeProperties = mView.mRenderNode != null;
 
             // alpha requires slightly different treatment than the other (transform) properties.
             // The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
@@ -1101,7 +1101,7 @@
             // We track what kinds of properties are set, and how alpha is handled when it is
             // set, and perform the invalidation steps appropriately.
             boolean alphaHandled = false;
-            if (!useDisplayListProperties) {
+            if (!useRenderNodeProperties) {
                 mView.invalidateParentCaches();
             }
             float fraction = animation.getAnimatedFraction();
@@ -1124,7 +1124,7 @@
             }
             if ((propertyMask & TRANSFORM_MASK) != 0) {
                 mView.mTransformationInfo.mMatrixDirty = true;
-                if (!useDisplayListProperties) {
+                if (!useRenderNodeProperties) {
                     mView.mPrivateFlags |= View.PFLAG_DRAWN; // force another invalidation
                 }
             }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e0e523e..a35c28e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1465,8 +1465,8 @@
                                     mWidth, mHeight);
                         }
                         mResizeBuffer.prepare(mWidth, mHeight, false);
-                        RenderNode layerDisplayList = mResizeBuffer.startRecording();
-                        HardwareCanvas layerCanvas = layerDisplayList.start(mWidth, mHeight);
+                        RenderNode layerRenderNode = mResizeBuffer.startRecording();
+                        HardwareCanvas layerCanvas = layerRenderNode.start(mWidth, mHeight);
                         final int restoreCount = layerCanvas.save();
 
                         int yoff;
@@ -1484,9 +1484,9 @@
                             mTranslator.translateCanvas(layerCanvas);
                         }
 
-                        RenderNode displayList = mView.mDisplayList;
-                        if (displayList != null && displayList.isValid()) {
-                            layerCanvas.drawDisplayList(displayList, null,
+                        RenderNode renderNode = mView.mRenderNode;
+                        if (renderNode != null && renderNode.isValid()) {
+                            layerCanvas.drawDisplayList(renderNode, null,
                                     RenderNode.FLAG_CLIP_CHILDREN);
                         } else {
                             mView.draw(layerCanvas);
@@ -1499,9 +1499,9 @@
                                 com.android.internal.R.integer.config_mediumAnimTime);
 
                         layerCanvas.restoreToCount(restoreCount);
-                        layerDisplayList.end(mAttachInfo.mHardwareRenderer, layerCanvas);
-                        layerDisplayList.setCaching(true);
-                        layerDisplayList.setLeftTopRightBottom(0, 0, mWidth, mHeight);
+                        layerRenderNode.end(mAttachInfo.mHardwareRenderer, layerCanvas);
+                        layerRenderNode.setCaching(true);
+                        layerRenderNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
                         mTempRect.set(0, 0, mWidth, mHeight);
                         mResizeBuffer.endRecording(mTempRect);
                         mAttachInfo.mHardwareRenderer.flushLayerUpdates();
@@ -2178,9 +2178,9 @@
      * @hide
      */
     void outputDisplayList(View view) {
-        RenderNode displayList = view.getDisplayList();
-        if (displayList != null) {
-            displayList.output();
+        RenderNode renderNode = view.getDisplayList();
+        if (renderNode != null) {
+            renderNode.output();
         }
     }
 
@@ -5218,10 +5218,10 @@
     }
 
     private static void getGfxInfo(View view, int[] info) {
-        RenderNode displayList = view.mDisplayList;
+        RenderNode renderNode = view.mRenderNode;
         info[0]++;
-        if (displayList != null) {
-            info[1] += 0; /* TODO: Memory used by display lists */
+        if (renderNode != null) {
+            info[1] += 0; /* TODO: Memory used by RenderNodes (properties + DisplayLists) */
         }
 
         if (view instanceof ViewGroup) {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 333e631..14e7951c 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -25,6 +25,7 @@
 import android.text.SpannableString;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
 import com.android.internal.widget.EditableInputConnection;
 
 import android.R;
@@ -1341,7 +1342,7 @@
 
         if (layout instanceof DynamicLayout) {
             if (mTextDisplayLists == null) {
-                mTextDisplayLists = new TextDisplayList[ArrayUtils.idealObjectArraySize(0)];
+                mTextDisplayLists = ArrayUtils.emptyArray(TextDisplayList.class);
             }
 
             DynamicLayout dynamicLayout = (DynamicLayout) layout;
@@ -1441,10 +1442,7 @@
         }
 
         // No available index found, the pool has to grow
-        int newSize = ArrayUtils.idealIntArraySize(length + 1);
-        TextDisplayList[] displayLists = new TextDisplayList[newSize];
-        System.arraycopy(mTextDisplayLists, 0, displayLists, 0, length);
-        mTextDisplayLists = displayLists;
+        mTextDisplayLists = GrowingArrayUtils.append(mTextDisplayLists, length, null);
         return length;
     }
 
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 64953f8..b47177a 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -24,6 +24,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
+import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.IntProperty;
@@ -1225,6 +1226,15 @@
                 forwarding = onTouchForwarded(event) || !onForwardingStopped();
             } else {
                 forwarding = onTouchObserved(event) && onForwardingStarted();
+
+                if (forwarding) {
+                    // Make sure we cancel any ongoing source event stream.
+                    final long now = SystemClock.uptimeMillis();
+                    final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL,
+                            0.0f, 0.0f, 0);
+                    mSrc.onTouchEvent(e);
+                    e.recycle();
+                }
             }
 
             mForwarding = forwarding;
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 1eedc5d..d8a6867 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -1171,8 +1171,8 @@
                     || !mOnQueryChangeListener.onQueryTextSubmit(query.toString())) {
                 if (mSearchable != null) {
                     launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null, query.toString());
-                    setImeVisibility(false);
                 }
+                setImeVisibility(false);
                 dismissSuggestions();
             }
         }
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 1cda631..595f023 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -35,6 +35,7 @@
 import android.view.textservice.TextServicesManager;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
 
 import java.text.BreakIterator;
 import java.util.Locale;
@@ -105,9 +106,9 @@
         mTextView = textView;
 
         // Arbitrary: these arrays will automatically double their sizes on demand
-        final int size = ArrayUtils.idealObjectArraySize(1);
-        mIds = new int[size];
-        mSpellCheckSpans = new SpellCheckSpan[size];
+        final int size = 1;
+        mIds = ArrayUtils.newUnpaddedIntArray(size);
+        mSpellCheckSpans = new SpellCheckSpan[mIds.length];
 
         setLocale(mTextView.getSpellCheckerLocale());
 
@@ -184,17 +185,9 @@
             if (mIds[i] < 0) return i;
         }
 
-        if (mLength == mSpellCheckSpans.length) {
-            final int newSize = mLength * 2;
-            int[] newIds = new int[newSize];
-            SpellCheckSpan[] newSpellCheckSpans = new SpellCheckSpan[newSize];
-            System.arraycopy(mIds, 0, newIds, 0, mLength);
-            System.arraycopy(mSpellCheckSpans, 0, newSpellCheckSpans, 0, mLength);
-            mIds = newIds;
-            mSpellCheckSpans = newSpellCheckSpans;
-        }
-
-        mSpellCheckSpans[mLength] = new SpellCheckSpan();
+        mIds = GrowingArrayUtils.append(mIds, mLength, 0);
+        mSpellCheckSpans = GrowingArrayUtils.append(
+                mSpellCheckSpans, mLength, new SpellCheckSpan());
         mLength++;
         return mLength - 1;
     }
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index b1535e3..882bec9 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -29,8 +29,11 @@
 import android.util.SparseArray;
 import android.util.TimeUtils;
 import android.webkit.WebViewFactory;
-import com.android.internal.util.ArrayUtils;
+
+import com.android.internal.util.GrowingArrayUtils;
+
 import dalvik.system.VMRuntime;
+import libcore.util.EmptyArray;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -1621,21 +1624,10 @@
     }
 
     int addLongData(int index, int type, int num) {
-        int tableLen = mAddLongTable != null ? mAddLongTable.length : 0;
-        if (mAddLongTableSize >= tableLen) {
-            int newSize = ArrayUtils.idealIntArraySize(tableLen + 1);
-            int[] newTable = new int[newSize];
-            if (tableLen > 0) {
-                System.arraycopy(mAddLongTable, 0, newTable, 0, tableLen);
-            }
-            mAddLongTable = newTable;
-        }
-        if (mAddLongTableSize > 0 && mAddLongTableSize - index != 0) {
-            System.arraycopy(mAddLongTable, index, mAddLongTable, index + 1,
-                    mAddLongTableSize - index);
-        }
         int off = allocLongData(num);
-        mAddLongTable[index] = type | off;
+        mAddLongTable = GrowingArrayUtils.insert(
+                mAddLongTable != null ? mAddLongTable : EmptyArray.INT,
+                mAddLongTableSize, index, type | off);
         mAddLongTableSize++;
         return off;
     }
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 03a053c..f9e5569 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -504,7 +504,7 @@
 
         private String mEnabledInputMethodsStrCache;
         private int mCurrentUserId;
-        private int[] mRelatedUserIds = new int[0];
+        private int[] mCurrentProfileIds = new int[0];
 
         private static void buildEnabledInputMethodsSettingString(
                 StringBuilder builder, Pair<String, ArrayList<String>> pair) {
@@ -537,17 +537,16 @@
             mCurrentUserId = userId;
         }
 
-        public void setRelatedUserIds(int[] relatedUserIds) {
+        public void setCurrentProfileIds(int[] currentProfileIds) {
             synchronized (this) {
-                mRelatedUserIds = relatedUserIds;
+                mCurrentProfileIds = currentProfileIds;
             }
         }
 
-        public boolean isRelatedToOrCurrentUser(int userId) {
+        public boolean isCurrentProfile(int userId) {
             synchronized (this) {
-                if (userId == mCurrentUserId) return true;
-                for (int i = 0; i < mRelatedUserIds.length; i++) {
-                    if (userId == mRelatedUserIds[i]) return true;
+                for (int i = 0; i < mCurrentProfileIds.length; i++) {
+                    if (userId == mCurrentProfileIds[i]) return true;
                 }
                 return false;
             }
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index 1766f7b..3301cbe 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -26,8 +26,6 @@
 
 import libcore.io.IoUtils;
 
-import dalvik.system.Zygote;
-
 /**
  * Startup class for the wrapper process.
  * @hide
@@ -94,7 +92,7 @@
      * @param niceName The nice name for the application, or null if none.
      * @param targetSdkVersion The target SDK version for the app.
      * @param pipeFd The pipe to which the application's pid should be written, or null if none.
-     * @param args Arguments for {@link RuntimeInit.main}.
+     * @param args Arguments for {@link RuntimeInit#main}.
      */
     public static void execApplication(String invokeWith, String niceName,
             int targetSdkVersion, FileDescriptor pipeFd, String[] args) {
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
new file mode 100644
index 0000000..c5fa0a1
--- /dev/null
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -0,0 +1,164 @@
+/*
+ * 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.internal.os;
+
+
+import dalvik.system.ZygoteHooks;
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
+
+/** @hide */
+public final class Zygote {
+    /*
+    * Bit values for "debugFlags" argument.  The definitions are duplicated
+    * in the native code.
+    */
+
+    /** enable debugging over JDWP */
+    public static final int DEBUG_ENABLE_DEBUGGER   = 1;
+    /** enable JNI checks */
+    public static final int DEBUG_ENABLE_CHECKJNI   = 1 << 1;
+    /** enable Java programming language "assert" statements */
+    public static final int DEBUG_ENABLE_ASSERT     = 1 << 2;
+    /** disable the JIT compiler */
+    public static final int DEBUG_ENABLE_SAFEMODE   = 1 << 3;
+    /** Enable logging of third-party JNI activity. */
+    public static final int DEBUG_ENABLE_JNI_LOGGING = 1 << 4;
+
+    /** No external storage should be mounted. */
+    public static final int MOUNT_EXTERNAL_NONE = 0;
+    /** Single-user external storage should be mounted. */
+    public static final int MOUNT_EXTERNAL_SINGLEUSER = 1;
+    /** Multi-user external storage should be mounted. */
+    public static final int MOUNT_EXTERNAL_MULTIUSER = 2;
+    /** All multi-user external storage should be mounted. */
+    public static final int MOUNT_EXTERNAL_MULTIUSER_ALL = 3;
+
+    private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();
+
+    private Zygote() {}
+
+    /**
+     * Forks a new VM instance.  The current VM must have been started
+     * with the -Xzygote flag. <b>NOTE: new instance keeps all
+     * root capabilities. The new process is expected to call capset()</b>.
+     *
+     * @param uid the UNIX uid that the new process should setuid() to after
+     * fork()ing and and before spawning any threads.
+     * @param gid the UNIX gid that the new process should setgid() to after
+     * fork()ing and and before spawning any threads.
+     * @param gids null-ok; a list of UNIX gids that the new process should
+     * setgroups() to after fork and before spawning any threads.
+     * @param debugFlags bit flags that enable debugging features.
+     * @param rlimits null-ok an array of rlimit tuples, with the second
+     * dimension having a length of 3 and representing
+     * (resource, rlim_cur, rlim_max). These are set via the posix
+     * setrlimit(2) call.
+     * @param seInfo null-ok a string specifying SELinux information for
+     * the new process.
+     * @param niceName null-ok a string specifying the process name.
+     * @param fdsToClose an array of ints, holding one or more POSIX
+     * file descriptor numbers that are to be closed by the child
+     * (and replaced by /dev/null) after forking.  An integer value
+     * of -1 in any entry in the array means "ignore this one".
+     *
+     * @return 0 if this is the child, pid of the child
+     * if this is the parent, or -1 on error.
+     */
+    public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
+          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose) {
+        VM_HOOKS.preFork();
+        int pid = nativeForkAndSpecialize(
+                  uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose);
+        VM_HOOKS.postForkCommon();
+        return pid;
+    }
+
+    native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int debugFlags,
+          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose);
+
+    /**
+     * Special method to start the system server process. In addition to the
+     * common actions performed in forkAndSpecialize, the pid of the child
+     * process is recorded such that the death of the child process will cause
+     * zygote to exit.
+     *
+     * @param uid the UNIX uid that the new process should setuid() to after
+     * fork()ing and and before spawning any threads.
+     * @param gid the UNIX gid that the new process should setgid() to after
+     * fork()ing and and before spawning any threads.
+     * @param gids null-ok; a list of UNIX gids that the new process should
+     * setgroups() to after fork and before spawning any threads.
+     * @param debugFlags bit flags that enable debugging features.
+     * @param rlimits null-ok an array of rlimit tuples, with the second
+     * dimension having a length of 3 and representing
+     * (resource, rlim_cur, rlim_max). These are set via the posix
+     * setrlimit(2) call.
+     * @param permittedCapabilities argument for setcap()
+     * @param effectiveCapabilities argument for setcap()
+     *
+     * @return 0 if this is the child, pid of the child
+     * if this is the parent, or -1 on error.
+     */
+    public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,
+            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
+        VM_HOOKS.preFork();
+        int pid = nativeForkSystemServer(
+                uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
+        VM_HOOKS.postForkCommon();
+        return pid;
+    }
+
+    native private static int nativeForkSystemServer(int uid, int gid, int[] gids, int debugFlags,
+            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
+
+    private static void callPostForkChildHooks(int debugFlags) {
+        VM_HOOKS.postForkChild(debugFlags);
+    }
+
+
+    /**
+     * Executes "/system/bin/sh -c &lt;command&gt;" using the exec() system call.
+     * This method throws a runtime exception if exec() failed, otherwise, this
+     * method never returns.
+     *
+     * @param command The shell command to execute.
+     */
+    public static void execShell(String command) {
+        String[] args = { "/system/bin/sh", "-c", command };
+        try {
+            Libcore.os.execv(args[0], args);
+        } catch (ErrnoException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Appends quotes shell arguments to the specified string builder.
+     * The arguments are quoted using single-quotes, escaped if necessary,
+     * prefixed with a space, and appended to the command.
+     *
+     * @param command A string builder for the shell command being constructed.
+     * @param args An array of argument strings to be quoted and appended to the command.
+     * @see #execShell(String)
+     */
+    public static void appendQuotedShellArgs(StringBuilder command, String[] args) {
+        for (String arg : args) {
+            command.append(" '").append(arg.replace("'", "'\\''")).append("'");
+        }
+    }
+}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index f9a1f89..aad534c 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -24,7 +24,6 @@
 import android.util.Log;
 
 import dalvik.system.PathClassLoader;
-import dalvik.system.Zygote;
 
 import java.io.BufferedReader;
 import java.io.DataInputStream;
@@ -807,7 +806,7 @@
     /**
      * Applies invoke-with system properties to the zygote arguments.
      *
-     * @param parsedArgs non-null; zygote args
+     * @param args non-null; zygote args
      */
     public static void applyInvokeWithSystemProperty(Arguments args) {
         if (args.invokeWith == null && args.niceName != null) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 05c57e8..66cc120 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -32,7 +32,6 @@
 import android.util.Log;
 
 import dalvik.system.VMRuntime;
-import dalvik.system.Zygote;
 
 import libcore.io.IoUtils;
 import libcore.io.Libcore;
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 9137d3c..d177410 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -16,11 +16,10 @@
 
 package com.android.internal.util;
 
-import java.lang.reflect.Array;
+import dalvik.system.VMRuntime;
+import libcore.util.EmptyArray;
 
-// XXX these should be changed to reflect the actual memory allocator we use.
-// it looks like right now objects want to be powers of 2 minus 8
-// and the array size eats another 4 bytes
+import java.lang.reflect.Array;
 
 /**
  * ArrayUtils contains some methods that you can call to find out
@@ -28,46 +27,42 @@
  */
 public class ArrayUtils
 {
-    private static Object[] EMPTY = new Object[0];
     private static final int CACHE_SIZE = 73;
     private static Object[] sCache = new Object[CACHE_SIZE];
 
     private ArrayUtils() { /* cannot be instantiated */ }
 
-    public static int idealByteArraySize(int need) {
-        for (int i = 4; i < 32; i++)
-            if (need <= (1 << i) - 12)
-                return (1 << i) - 12;
-
-        return need;
+    public static byte[] newUnpaddedByteArray(int minLen) {
+        return (byte[])VMRuntime.getRuntime().newUnpaddedArray(byte.class, minLen);
     }
 
-    public static int idealBooleanArraySize(int need) {
-        return idealByteArraySize(need);
+    public static char[] newUnpaddedCharArray(int minLen) {
+        return (char[])VMRuntime.getRuntime().newUnpaddedArray(char.class, minLen);
     }
 
-    public static int idealShortArraySize(int need) {
-        return idealByteArraySize(need * 2) / 2;
+    public static int[] newUnpaddedIntArray(int minLen) {
+        return (int[])VMRuntime.getRuntime().newUnpaddedArray(int.class, minLen);
     }
 
-    public static int idealCharArraySize(int need) {
-        return idealByteArraySize(need * 2) / 2;
+    public static boolean[] newUnpaddedBooleanArray(int minLen) {
+        return (boolean[])VMRuntime.getRuntime().newUnpaddedArray(boolean.class, minLen);
     }
 
-    public static int idealIntArraySize(int need) {
-        return idealByteArraySize(need * 4) / 4;
+    public static long[] newUnpaddedLongArray(int minLen) {
+        return (long[])VMRuntime.getRuntime().newUnpaddedArray(long.class, minLen);
     }
 
-    public static int idealFloatArraySize(int need) {
-        return idealByteArraySize(need * 4) / 4;
+    public static float[] newUnpaddedFloatArray(int minLen) {
+        return (float[])VMRuntime.getRuntime().newUnpaddedArray(float.class, minLen);
     }
 
-    public static int idealObjectArraySize(int need) {
-        return idealByteArraySize(need * 4) / 4;
+    public static Object[] newUnpaddedObjectArray(int minLen) {
+        return (Object[])VMRuntime.getRuntime().newUnpaddedArray(Object.class, minLen);
     }
 
-    public static int idealLongArraySize(int need) {
-        return idealByteArraySize(need * 8) / 8;
+    @SuppressWarnings("unchecked")
+    public static <T> T[] newUnpaddedArray(Class<T> clazz, int minLen) {
+        return (T[])VMRuntime.getRuntime().newUnpaddedArray(clazz, minLen);
     }
 
     /**
@@ -102,9 +97,10 @@
      * it will return the same empty array every time to avoid reallocation,
      * although this is not guaranteed.
      */
+    @SuppressWarnings("unchecked")
     public static <T> T[] emptyArray(Class<T> kind) {
         if (kind == Object.class) {
-            return (T[]) EMPTY;
+            return (T[]) EmptyArray.OBJECT;
         }
 
         int bucket = ((System.identityHashCode(kind) / 8) & 0x7FFFFFFF) % CACHE_SIZE;
diff --git a/core/java/com/android/internal/util/GrowingArrayUtils.java b/core/java/com/android/internal/util/GrowingArrayUtils.java
new file mode 100644
index 0000000..b4d2d730
--- /dev/null
+++ b/core/java/com/android/internal/util/GrowingArrayUtils.java
@@ -0,0 +1,196 @@
+/*
+ * 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.internal.util;
+
+/**
+ * A helper class that aims to provide comparable growth performance to ArrayList, but on primitive
+ * arrays. Common array operations are implemented for efficient use in dynamic containers.
+ *
+ * All methods in this class assume that the length of an array is equivalent to its capacity and
+ * NOT the number of elements in the array. The current size of the array is always passed in as a
+ * parameter.
+ *
+ * @hide
+ */
+public final class GrowingArrayUtils {
+
+    /**
+     * Appends an element to the end of the array, growing the array if there is no more room.
+     * @param array The array to which to append the element. This must NOT be null.
+     * @param currentSize The number of elements in the array. Must be less than or equal to
+     *                    array.length.
+     * @param element The element to append.
+     * @return the array to which the element was appended. This may be different than the given
+     *         array.
+     */
+    public static <T> T[] append(T[] array, int currentSize, T element) {
+        assert currentSize <= array.length;
+
+        if (currentSize + 1 > array.length) {
+            @SuppressWarnings("unchecked")
+            T[] newArray = ArrayUtils.newUnpaddedArray(
+                    (Class<T>) array.getClass().getComponentType(), growSize(currentSize));
+            System.arraycopy(array, 0, newArray, 0, currentSize);
+            array = newArray;
+        }
+        array[currentSize] = element;
+        return array;
+    }
+
+    /**
+     * Primitive int version of {@link #append(Object[], int, Object)}.
+     */
+    public static int[] append(int[] array, int currentSize, int element) {
+        assert currentSize <= array.length;
+
+        if (currentSize + 1 > array.length) {
+            int[] newArray = ArrayUtils.newUnpaddedIntArray(growSize(currentSize));
+            System.arraycopy(array, 0, newArray, 0, currentSize);
+            array = newArray;
+        }
+        array[currentSize] = element;
+        return array;
+    }
+
+    /**
+     * Primitive long version of {@link #append(Object[], int, Object)}.
+     */
+    public static long[] append(long[] array, int currentSize, long element) {
+        assert currentSize <= array.length;
+
+        if (currentSize + 1 > array.length) {
+            long[] newArray = ArrayUtils.newUnpaddedLongArray(growSize(currentSize));
+            System.arraycopy(array, 0, newArray, 0, currentSize);
+            array = newArray;
+        }
+        array[currentSize] = element;
+        return array;
+    }
+
+    /**
+     * Primitive boolean version of {@link #append(Object[], int, Object)}.
+     */
+    public static boolean[] append(boolean[] array, int currentSize, boolean element) {
+        assert currentSize <= array.length;
+
+        if (currentSize + 1 > array.length) {
+            boolean[] newArray = ArrayUtils.newUnpaddedBooleanArray(growSize(currentSize));
+            System.arraycopy(array, 0, newArray, 0, currentSize);
+            array = newArray;
+        }
+        array[currentSize] = element;
+        return array;
+    }
+
+    /**
+     * Inserts an element into the array at the specified index, growing the array if there is no
+     * more room.
+     *
+     * @param array The array to which to append the element. Must NOT be null.
+     * @param currentSize The number of elements in the array. Must be less than or equal to
+     *                    array.length.
+     * @param element The element to insert.
+     * @return the array to which the element was appended. This may be different than the given
+     *         array.
+     */
+    public static <T> T[] insert(T[] array, int currentSize, int index, T element) {
+        assert currentSize <= array.length;
+
+        if (currentSize + 1 <= array.length) {
+            System.arraycopy(array, index, array, index + 1, currentSize - index);
+            array[index] = element;
+            return array;
+        }
+
+        @SuppressWarnings("unchecked")
+        T[] newArray = ArrayUtils.newUnpaddedArray((Class<T>)array.getClass().getComponentType(),
+                growSize(currentSize));
+        System.arraycopy(array, 0, newArray, 0, index);
+        newArray[index] = element;
+        System.arraycopy(array, index, newArray, index + 1, array.length - index);
+        return newArray;
+    }
+
+    /**
+     * Primitive int version of {@link #insert(Object[], int, int, Object)}.
+     */
+    public static int[] insert(int[] array, int currentSize, int index, int element) {
+        assert currentSize <= array.length;
+
+        if (currentSize + 1 <= array.length) {
+            System.arraycopy(array, index, array, index + 1, currentSize - index);
+            array[index] = element;
+            return array;
+        }
+
+        int[] newArray = ArrayUtils.newUnpaddedIntArray(growSize(currentSize));
+        System.arraycopy(array, 0, newArray, 0, index);
+        newArray[index] = element;
+        System.arraycopy(array, index, newArray, index + 1, array.length - index);
+        return newArray;
+    }
+
+    /**
+     * Primitive long version of {@link #insert(Object[], int, int, Object)}.
+     */
+    public static long[] insert(long[] array, int currentSize, int index, long element) {
+        assert currentSize <= array.length;
+
+        if (currentSize + 1 <= array.length) {
+            System.arraycopy(array, index, array, index + 1, currentSize - index);
+            array[index] = element;
+            return array;
+        }
+
+        long[] newArray = ArrayUtils.newUnpaddedLongArray(growSize(currentSize));
+        System.arraycopy(array, 0, newArray, 0, index);
+        newArray[index] = element;
+        System.arraycopy(array, index, newArray, index + 1, array.length - index);
+        return newArray;
+    }
+
+    /**
+     * Primitive boolean version of {@link #insert(Object[], int, int, Object)}.
+     */
+    public static boolean[] insert(boolean[] array, int currentSize, int index, boolean element) {
+        assert currentSize <= array.length;
+
+        if (currentSize + 1 <= array.length) {
+            System.arraycopy(array, index, array, index + 1, currentSize - index);
+            array[index] = element;
+            return array;
+        }
+
+        boolean[] newArray = ArrayUtils.newUnpaddedBooleanArray(growSize(currentSize));
+        System.arraycopy(array, 0, newArray, 0, index);
+        newArray[index] = element;
+        System.arraycopy(array, index, newArray, index + 1, array.length - index);
+        return newArray;
+    }
+
+    /**
+     * Given the current size of an array, returns an ideal size to which the array should grow.
+     * This is typically double the given size, but should not be relied upon to do so in the
+     * future.
+     */
+    public static int growSize(int currentSize) {
+        return currentSize <= 4 ? 8 : currentSize * 2;
+    }
+
+    // Uninstantiable
+    private GrowingArrayUtils() {}
+}
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 91056f1..9501f92 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -28,6 +28,7 @@
     boolean checkPattern(in String pattern, int userId);
     void setLockPassword(in String password, int userId);
     boolean checkPassword(in String password, int userId);
+    boolean checkVoldPassword(int userId);
     boolean havePattern(int userId);
     boolean havePassword(int userId);
     void removeUser(int userId);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 2d79491..b9bc54d 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -19,11 +19,14 @@
 import android.Manifest;
 import android.app.ActivityManagerNative;
 import android.app.admin.DevicePolicyManager;
+import android.app.trust.TrustManager;
 import android.appwidget.AppWidgetManager;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.net.Uri;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -46,6 +49,8 @@
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -145,6 +150,8 @@
     private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
             Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
 
+    private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
+
     private final Context mContext;
     private final ContentResolver mContentResolver;
     private DevicePolicyManager mDevicePolicyManager;
@@ -167,6 +174,15 @@
         return mDevicePolicyManager;
     }
 
+    private TrustManager getTrustManager() {
+        TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
+        if (trust == null) {
+            Log.e(TAG, "Can't get TrustManagerService: is it running?",
+                    new IllegalStateException("Stack trace:"));
+        }
+        return trust;
+    }
+
     /**
      * @param contentResolver Used to look up and save settings.
      */
@@ -242,10 +258,14 @@
      */
     public void reportFailedPasswordAttempt() {
         getDevicePolicyManager().reportFailedPasswordAttempt(getCurrentOrCallingUserId());
+        getTrustManager().reportUnlockAttempt(false /* authenticated */,
+                getCurrentOrCallingUserId());
     }
 
     public void reportSuccessfulPasswordAttempt() {
         getDevicePolicyManager().reportSuccessfulPasswordAttempt(getCurrentOrCallingUserId());
+        getTrustManager().reportUnlockAttempt(true /* authenticated */,
+                getCurrentOrCallingUserId());
     }
 
     public void setCurrentUser(int userId) {
@@ -313,6 +333,20 @@
     }
 
     /**
+     * Check to see if vold already has the password.
+     * Note that this also clears vold's copy of the password.
+     * @return Whether the vold password matches or not.
+     */
+    public boolean checkVoldPassword() {
+        final int userId = getCurrentOrCallingUserId();
+        try {
+            return getLockSettings().checkVoldPassword(userId);
+        } catch (RemoteException re) {
+            return false;
+        }
+    }
+
+    /**
      * Check to see if a password matches any of the passwords stored in the
      * password history.
      *
@@ -496,11 +530,12 @@
      */
     public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) {
         try {
-            getLockSettings().setLockPattern(patternToString(pattern), getCurrentOrCallingUserId());
+            int userId = getCurrentOrCallingUserId();
+            getLockSettings().setLockPattern(patternToString(pattern), userId);
             DevicePolicyManager dpm = getDevicePolicyManager();
             if (pattern != null) {
 
-                int userHandle = getCurrentOrCallingUserId();
+                int userHandle = userId;
                 if (userHandle == UserHandle.USER_OWNER) {
                     String stringPattern = patternToString(pattern);
                     updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
@@ -511,18 +546,18 @@
                     deleteGallery();
                     setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
                     dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
-                            pattern.size(), 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
+                            pattern.size(), 0, 0, 0, 0, 0, 0, userId);
                 } else {
                     setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
                     setLong(PASSWORD_TYPE_ALTERNATE_KEY,
                             DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
                     finishBiometricWeak();
                     dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
-                            0, 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
+                            0, 0, 0, 0, 0, 0, 0, userId);
                 }
             } else {
                 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0,
-                        0, 0, 0, 0, 0, getCurrentOrCallingUserId());
+                        0, 0, 0, 0, 0, userId);
             }
         } catch (RemoteException re) {
             Log.e(TAG, "Couldn't save lock pattern " + re);
@@ -1374,4 +1409,38 @@
         setBoolean(LOCKSCREEN_WIDGETS_ENABLED, enabled, userId);
     }
 
+    public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents) {
+        setEnabledTrustAgents(activeTrustAgents, getCurrentOrCallingUserId());
+    }
+
+    public List<ComponentName> getEnabledTrustAgents() {
+        return getEnabledTrustAgents(getCurrentOrCallingUserId());
+    }
+
+    public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
+        StringBuilder sb = new StringBuilder();
+        for (ComponentName cn : activeTrustAgents) {
+            if (sb.length() > 0) {
+                sb.append(',');
+            }
+            sb.append(cn.flattenToShortString());
+        }
+        setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
+        getTrustManager().reportEnabledTrustAgentsChanged(getCurrentOrCallingUserId());
+    }
+
+    public List<ComponentName> getEnabledTrustAgents(int userId) {
+        String serialized = getString(ENABLED_TRUST_AGENTS, userId);
+        if (TextUtils.isEmpty(serialized)) {
+            return null;
+        }
+        String[] split = serialized.split(",");
+        ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
+        for (String s : split) {
+            if (!TextUtils.isEmpty(s)) {
+                activeTrustAgents.add(ComponentName.unflattenFromString(s));
+            }
+        }
+        return activeTrustAgents;
+    }
 }
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 26cb4e5..36ed344 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -32,6 +32,7 @@
 import android.os.Parcelable;
 import android.os.SystemClock;
 import android.util.AttributeSet;
+import android.util.TypedValue;
 import android.view.HapticFeedbackConstants;
 import android.view.MotionEvent;
 import android.view.View;
@@ -260,13 +261,23 @@
 
         mPathPaint.setAntiAlias(true);
         mPathPaint.setDither(true);
-        mPathPaint.setColor(Color.WHITE);   // TODO this should be from the style
+
+        int defaultColor = Color.WHITE;
+        TypedValue outValue = new TypedValue();
+        if (context.getTheme().resolveAttribute(android.R.attr.textColorPrimary, outValue, true)) {
+            defaultColor = context.getResources().getColor(outValue.resourceId);
+        }
+
+        final int color = a.getColor(R.styleable.LockPatternView_pathColor, defaultColor);
+        mPathPaint.setColor(color);
+
         mPathPaint.setAlpha(mStrokeAlpha);
         mPathPaint.setStyle(Paint.Style.STROKE);
         mPathPaint.setStrokeJoin(Paint.Join.ROUND);
         mPathPaint.setStrokeCap(Paint.Cap.ROUND);
 
         // lot's of bitmaps!
+        // TODO: those bitmaps are hardcoded to the Holo Theme which should not be the case!
         mBitmapBtnDefault = getBitmapFor(R.drawable.btn_code_lock_default_holo);
         mBitmapBtnTouched = getBitmapFor(R.drawable.btn_code_lock_touched_holo);
         mBitmapCircleDefault = getBitmapFor(R.drawable.indicator_code_lock_point_area_default_holo);
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
deleted file mode 100644
index 4648f39..0000000
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ /dev/null
@@ -1,1270 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget.multiwaveview;
-
-import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.os.Vibrator;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-
-import com.android.internal.R;
-
-import java.util.ArrayList;
-
-/**
- * A special widget containing a center and outer ring. Moving the center ring to the outer ring
- * causes an event that can be caught by implementing OnTriggerListener.
- */
-public class MultiWaveView extends View {
-    private static final String TAG = "MultiWaveView";
-    private static final boolean DEBUG = false;
-
-    // Wave state machine
-    private static final int STATE_IDLE = 0;
-    private static final int STATE_START = 1;
-    private static final int STATE_FIRST_TOUCH = 2;
-    private static final int STATE_TRACKING = 3;
-    private static final int STATE_SNAP = 4;
-    private static final int STATE_FINISH = 5;
-
-    // Animation properties.
-    private static final float SNAP_MARGIN_DEFAULT = 20.0f; // distance to ring before we snap to it
-
-    public interface OnTriggerListener {
-        int NO_HANDLE = 0;
-        int CENTER_HANDLE = 1;
-        public void onGrabbed(View v, int handle);
-        public void onReleased(View v, int handle);
-        public void onTrigger(View v, int target);
-        public void onGrabbedStateChange(View v, int handle);
-        public void onFinishFinalAnimation();
-    }
-
-    // Tuneable parameters for animation
-    private static final int CHEVRON_INCREMENTAL_DELAY = 160;
-    private static final int CHEVRON_ANIMATION_DURATION = 850;
-    private static final int RETURN_TO_HOME_DELAY = 1200;
-    private static final int RETURN_TO_HOME_DURATION = 200;
-    private static final int HIDE_ANIMATION_DELAY = 200;
-    private static final int HIDE_ANIMATION_DURATION = 200;
-    private static final int SHOW_ANIMATION_DURATION = 200;
-    private static final int SHOW_ANIMATION_DELAY = 50;
-    private static final int INITIAL_SHOW_HANDLE_DURATION = 200;
-
-    private static final float TAP_RADIUS_SCALE_ACCESSIBILITY_ENABLED = 1.3f;
-    private static final float TARGET_SCALE_EXPANDED = 1.0f;
-    private static final float TARGET_SCALE_COLLAPSED = 0.8f;
-    private static final float RING_SCALE_EXPANDED = 1.0f;
-    private static final float RING_SCALE_COLLAPSED = 0.5f;
-
-    private TimeInterpolator mChevronAnimationInterpolator = Ease.Quad.easeOut;
-
-    private ArrayList<TargetDrawable> mTargetDrawables = new ArrayList<TargetDrawable>();
-    private ArrayList<TargetDrawable> mChevronDrawables = new ArrayList<TargetDrawable>();
-    private AnimationBundle mChevronAnimations = new AnimationBundle();
-    private AnimationBundle mTargetAnimations = new AnimationBundle();
-    private AnimationBundle mHandleAnimations = new AnimationBundle();
-    private ArrayList<String> mTargetDescriptions;
-    private ArrayList<String> mDirectionDescriptions;
-    private OnTriggerListener mOnTriggerListener;
-    private TargetDrawable mHandleDrawable;
-    private TargetDrawable mOuterRing;
-    private Vibrator mVibrator;
-
-    private int mFeedbackCount = 3;
-    private int mVibrationDuration = 0;
-    private int mGrabbedState;
-    private int mActiveTarget = -1;
-    private float mTapRadius;
-    private float mWaveCenterX;
-    private float mWaveCenterY;
-    private int mMaxTargetHeight;
-    private int mMaxTargetWidth;
-
-    private float mOuterRadius = 0.0f;
-    private float mSnapMargin = 0.0f;
-    private boolean mDragging;
-    private int mNewTargetResources;
-
-    private class AnimationBundle extends ArrayList<Tweener> {
-        private static final long serialVersionUID = 0xA84D78726F127468L;
-        private boolean mSuspended;
-
-        public void start() {
-            if (mSuspended) return; // ignore attempts to start animations
-            final int count = size();
-            for (int i = 0; i < count; i++) {
-                Tweener anim = get(i);
-                anim.animator.start();
-            }
-        }
-
-        public void cancel() {
-            final int count = size();
-            for (int i = 0; i < count; i++) {
-                Tweener anim = get(i);
-                anim.animator.cancel();
-            }
-            clear();
-        }
-
-        public void stop() {
-            final int count = size();
-            for (int i = 0; i < count; i++) {
-                Tweener anim = get(i);
-                anim.animator.end();
-            }
-            clear();
-        }
-
-        public void setSuspended(boolean suspend) {
-            mSuspended = suspend;
-        }
-    };
-
-    private AnimatorListener mResetListener = new AnimatorListenerAdapter() {
-        public void onAnimationEnd(Animator animator) {
-            switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY);
-            dispatchOnFinishFinalAnimation();
-        }
-    };
-
-    private AnimatorListener mResetListenerWithPing = new AnimatorListenerAdapter() {
-        public void onAnimationEnd(Animator animator) {
-            ping();
-            switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY);
-            dispatchOnFinishFinalAnimation();
-        }
-    };
-
-    private AnimatorUpdateListener mUpdateListener = new AnimatorUpdateListener() {
-        public void onAnimationUpdate(ValueAnimator animation) {
-            invalidateGlobalRegion(mHandleDrawable);
-            invalidate();
-        }
-    };
-
-    private boolean mAnimatingTargets;
-    private AnimatorListener mTargetUpdateListener = new AnimatorListenerAdapter() {
-        public void onAnimationEnd(Animator animator) {
-            if (mNewTargetResources != 0) {
-                internalSetTargetResources(mNewTargetResources);
-                mNewTargetResources = 0;
-                hideTargets(false, false);
-            }
-            mAnimatingTargets = false;
-        }
-    };
-    private int mTargetResourceId;
-    private int mTargetDescriptionsResourceId;
-    private int mDirectionDescriptionsResourceId;
-    private boolean mAlwaysTrackFinger;
-    private int mHorizontalInset;
-    private int mVerticalInset;
-    private int mGravity = Gravity.TOP;
-    private boolean mInitialLayout = true;
-    private Tweener mBackgroundAnimator;
-
-    public MultiWaveView(Context context) {
-        this(context, null);
-    }
-
-    public MultiWaveView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        Resources res = context.getResources();
-
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MultiWaveView);
-        mOuterRadius = a.getDimension(R.styleable.MultiWaveView_outerRadius, mOuterRadius);
-        mSnapMargin = a.getDimension(R.styleable.MultiWaveView_snapMargin, mSnapMargin);
-        mVibrationDuration = a.getInt(R.styleable.MultiWaveView_vibrationDuration,
-                mVibrationDuration);
-        mFeedbackCount = a.getInt(R.styleable.MultiWaveView_feedbackCount,
-                mFeedbackCount);
-        mHandleDrawable = new TargetDrawable(res,
-                a.peekValue(R.styleable.MultiWaveView_handleDrawable).resourceId);
-        mTapRadius = mHandleDrawable.getWidth()/2;
-        mOuterRing = new TargetDrawable(res,
-                a.peekValue(R.styleable.MultiWaveView_waveDrawable).resourceId);
-        mAlwaysTrackFinger = a.getBoolean(R.styleable.MultiWaveView_alwaysTrackFinger, false);
-
-        // Read array of chevron drawables
-        TypedValue outValue = new TypedValue();
-        if (a.getValue(R.styleable.MultiWaveView_chevronDrawables, outValue)) {
-            ArrayList<TargetDrawable> chevrons = loadDrawableArray(outValue.resourceId);
-            for (int i = 0; i < chevrons.size(); i++) {
-                final TargetDrawable chevron = chevrons.get(i);
-                for (int k = 0; k < mFeedbackCount; k++) {
-                    mChevronDrawables.add(chevron == null ? null : new TargetDrawable(chevron));
-                }
-            }
-        }
-
-        // Read array of target drawables
-        if (a.getValue(R.styleable.MultiWaveView_targetDrawables, outValue)) {
-            internalSetTargetResources(outValue.resourceId);
-        }
-        if (mTargetDrawables == null || mTargetDrawables.size() == 0) {
-            throw new IllegalStateException("Must specify at least one target drawable");
-        }
-
-        // Read array of target descriptions
-        if (a.getValue(R.styleable.MultiWaveView_targetDescriptions, outValue)) {
-            final int resourceId = outValue.resourceId;
-            if (resourceId == 0) {
-                throw new IllegalStateException("Must specify target descriptions");
-            }
-            setTargetDescriptionsResourceId(resourceId);
-        }
-
-        // Read array of direction descriptions
-        if (a.getValue(R.styleable.MultiWaveView_directionDescriptions, outValue)) {
-            final int resourceId = outValue.resourceId;
-            if (resourceId == 0) {
-                throw new IllegalStateException("Must specify direction descriptions");
-            }
-            setDirectionDescriptionsResourceId(resourceId);
-        }
-
-        a.recycle();
-
-        // Use gravity attribute from LinearLayout
-        a = context.obtainStyledAttributes(attrs, android.R.styleable.LinearLayout);
-        mGravity = a.getInt(android.R.styleable.LinearLayout_gravity, Gravity.TOP);
-        a.recycle();
-
-        setVibrateEnabled(mVibrationDuration > 0);
-        assignDefaultsIfNeeded();
-    }
-
-    private void dump() {
-        Log.v(TAG, "Outer Radius = " + mOuterRadius);
-        Log.v(TAG, "SnapMargin = " + mSnapMargin);
-        Log.v(TAG, "FeedbackCount = " + mFeedbackCount);
-        Log.v(TAG, "VibrationDuration = " + mVibrationDuration);
-        Log.v(TAG, "TapRadius = " + mTapRadius);
-        Log.v(TAG, "WaveCenterX = " + mWaveCenterX);
-        Log.v(TAG, "WaveCenterY = " + mWaveCenterY);
-    }
-
-    public void suspendAnimations() {
-        mChevronAnimations.setSuspended(true);
-        mTargetAnimations.setSuspended(true);
-        mHandleAnimations.setSuspended(true);
-    }
-
-    public void resumeAnimations() {
-        mChevronAnimations.setSuspended(false);
-        mTargetAnimations.setSuspended(false);
-        mHandleAnimations.setSuspended(false);
-        mChevronAnimations.start();
-        mTargetAnimations.start();
-        mHandleAnimations.start();
-    }
-
-    @Override
-    protected int getSuggestedMinimumWidth() {
-        // View should be large enough to contain the background + handle and
-        // target drawable on either edge.
-        return (int) (Math.max(mOuterRing.getWidth(), 2 * mOuterRadius) + mMaxTargetWidth);
-    }
-
-    @Override
-    protected int getSuggestedMinimumHeight() {
-        // View should be large enough to contain the unlock ring + target and
-        // target drawable on either edge
-        return (int) (Math.max(mOuterRing.getHeight(), 2 * mOuterRadius) + mMaxTargetHeight);
-    }
-
-    private int resolveMeasured(int measureSpec, int desired)
-    {
-        int result = 0;
-        int specSize = MeasureSpec.getSize(measureSpec);
-        switch (MeasureSpec.getMode(measureSpec)) {
-            case MeasureSpec.UNSPECIFIED:
-                result = desired;
-                break;
-            case MeasureSpec.AT_MOST:
-                result = Math.min(specSize, desired);
-                break;
-            case MeasureSpec.EXACTLY:
-            default:
-                result = specSize;
-        }
-        return result;
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        final int minimumWidth = getSuggestedMinimumWidth();
-        final int minimumHeight = getSuggestedMinimumHeight();
-        int computedWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
-        int computedHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
-        computeInsets((computedWidth - minimumWidth), (computedHeight - minimumHeight));
-        setMeasuredDimension(computedWidth, computedHeight);
-    }
-
-    private void switchToState(int state, float x, float y) {
-        switch (state) {
-            case STATE_IDLE:
-                deactivateTargets();
-                hideTargets(true, false);
-                startBackgroundAnimation(0, 0.0f);
-                mHandleDrawable.setState(TargetDrawable.STATE_INACTIVE);
-                break;
-
-            case STATE_START:
-                deactivateHandle(0, 0, 1.0f, null);
-                startBackgroundAnimation(0, 0.0f);
-                break;
-
-            case STATE_FIRST_TOUCH:
-                deactivateTargets();
-                showTargets(true);
-                mHandleDrawable.setState(TargetDrawable.STATE_ACTIVE);
-                startBackgroundAnimation(INITIAL_SHOW_HANDLE_DURATION, 1.0f);
-                setGrabbedState(OnTriggerListener.CENTER_HANDLE);
-                if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                    announceTargets();
-                }
-                break;
-
-            case STATE_TRACKING:
-                break;
-
-            case STATE_SNAP:
-                break;
-
-            case STATE_FINISH:
-                doFinish();
-                break;
-        }
-    }
-
-    private void activateHandle(int duration, int delay, float finalAlpha,
-            AnimatorListener finishListener) {
-        mHandleAnimations.cancel();
-        mHandleAnimations.add(Tweener.to(mHandleDrawable, duration,
-                "ease", Ease.Cubic.easeIn,
-                "delay", delay,
-                "alpha", finalAlpha,
-                "onUpdate", mUpdateListener,
-                "onComplete", finishListener));
-        mHandleAnimations.start();
-    }
-
-    private void deactivateHandle(int duration, int delay, float finalAlpha,
-            AnimatorListener finishListener) {
-        mHandleAnimations.cancel();
-        mHandleAnimations.add(Tweener.to(mHandleDrawable, duration,
-            "ease", Ease.Quart.easeOut,
-            "delay", delay,
-            "alpha", finalAlpha,
-            "x", 0,
-            "y", 0,
-            "onUpdate", mUpdateListener,
-            "onComplete", finishListener));
-        mHandleAnimations.start();
-    }
-
-    /**
-     * Animation used to attract user's attention to the target button.
-     * Assumes mChevronDrawables is an a list with an even number of chevrons filled with
-     * mFeedbackCount items in the order: left, right, top, bottom.
-     */
-    private void startChevronAnimation() {
-        final float chevronStartDistance = mHandleDrawable.getWidth() * 0.8f;
-        final float chevronStopDistance = mOuterRadius * 0.9f / 2.0f;
-        final float startScale = 0.5f;
-        final float endScale = 2.0f;
-        final int directionCount = mFeedbackCount > 0 ? mChevronDrawables.size()/mFeedbackCount : 0;
-
-        mChevronAnimations.stop();
-
-        // Add an animation for all chevron drawables.  There are mFeedbackCount drawables
-        // in each direction and directionCount directions.
-        for (int direction = 0; direction < directionCount; direction++) {
-            double angle = 2.0 * Math.PI * direction / directionCount;
-            final float sx = (float) Math.cos(angle);
-            final float sy = 0.0f - (float) Math.sin(angle);
-            final float[] xrange = new float[]
-                 {sx * chevronStartDistance, sx * chevronStopDistance};
-            final float[] yrange = new float[]
-                 {sy * chevronStartDistance, sy * chevronStopDistance};
-            for (int count = 0; count < mFeedbackCount; count++) {
-                int delay = count * CHEVRON_INCREMENTAL_DELAY;
-                final TargetDrawable icon = mChevronDrawables.get(direction*mFeedbackCount + count);
-                if (icon == null) {
-                    continue;
-                }
-                mChevronAnimations.add(Tweener.to(icon, CHEVRON_ANIMATION_DURATION,
-                        "ease", mChevronAnimationInterpolator,
-                        "delay", delay,
-                        "x", xrange,
-                        "y", yrange,
-                        "alpha", new float[] {1.0f, 0.0f},
-                        "scaleX", new float[] {startScale, endScale},
-                        "scaleY", new float[] {startScale, endScale},
-                        "onUpdate", mUpdateListener));
-            }
-        }
-        mChevronAnimations.start();
-    }
-
-    private void deactivateTargets() {
-        final int count = mTargetDrawables.size();
-        for (int i = 0; i < count; i++) {
-            TargetDrawable target = mTargetDrawables.get(i);
-            target.setState(TargetDrawable.STATE_INACTIVE);
-        }
-        mActiveTarget = -1;
-    }
-
-    void invalidateGlobalRegion(TargetDrawable drawable) {
-        int width = drawable.getWidth();
-        int height = drawable.getHeight();
-        RectF childBounds = new RectF(0, 0, width, height);
-        childBounds.offset(drawable.getX() - width/2, drawable.getY() - height/2);
-        View view = this;
-        while (view.getParent() != null && view.getParent() instanceof View) {
-            view = (View) view.getParent();
-            view.getMatrix().mapRect(childBounds);
-            view.invalidate((int) Math.floor(childBounds.left),
-                    (int) Math.floor(childBounds.top),
-                    (int) Math.ceil(childBounds.right),
-                    (int) Math.ceil(childBounds.bottom));
-        }
-    }
-
-    /**
-     * Dispatches a trigger event to listener. Ignored if a listener is not set.
-     * @param whichTarget the target that was triggered.
-     */
-    private void dispatchTriggerEvent(int whichTarget) {
-        vibrate();
-        if (mOnTriggerListener != null) {
-            mOnTriggerListener.onTrigger(this, whichTarget);
-        }
-    }
-
-    private void dispatchOnFinishFinalAnimation() {
-        if (mOnTriggerListener != null) {
-            mOnTriggerListener.onFinishFinalAnimation();
-        }
-    }
-
-    private void doFinish() {
-        final int activeTarget = mActiveTarget;
-        final boolean targetHit =  activeTarget != -1;
-
-        if (targetHit) {
-            if (DEBUG) Log.v(TAG, "Finish with target hit = " + targetHit);
-
-            highlightSelected(activeTarget);
-
-            // Inform listener of any active targets.  Typically only one will be active.
-            deactivateHandle(RETURN_TO_HOME_DURATION, RETURN_TO_HOME_DELAY, 0.0f, mResetListener);
-            dispatchTriggerEvent(activeTarget);
-            if (!mAlwaysTrackFinger) {
-                // Force ring and targets to finish animation to final expanded state
-                mTargetAnimations.stop();
-            }
-        } else {
-            // Animate handle back to the center based on current state.
-            deactivateHandle(HIDE_ANIMATION_DURATION, HIDE_ANIMATION_DELAY, 1.0f,
-                    mResetListenerWithPing);
-            hideTargets(true, false);
-        }
-
-        setGrabbedState(OnTriggerListener.NO_HANDLE);
-    }
-
-    private void highlightSelected(int activeTarget) {
-        // Highlight the given target and fade others
-        mTargetDrawables.get(activeTarget).setState(TargetDrawable.STATE_ACTIVE);
-        hideUnselected(activeTarget);
-    }
-
-    private void hideUnselected(int active) {
-        for (int i = 0; i < mTargetDrawables.size(); i++) {
-            if (i != active) {
-                mTargetDrawables.get(i).setAlpha(0.0f);
-            }
-        }
-    }
-
-    private void hideTargets(boolean animate, boolean expanded) {
-        mTargetAnimations.cancel();
-        // Note: these animations should complete at the same time so that we can swap out
-        // the target assets asynchronously from the setTargetResources() call.
-        mAnimatingTargets = animate;
-        final int duration = animate ? HIDE_ANIMATION_DURATION : 0;
-        final int delay = animate ? HIDE_ANIMATION_DELAY : 0;
-
-        final float targetScale = expanded ? TARGET_SCALE_EXPANDED : TARGET_SCALE_COLLAPSED;
-        final int length = mTargetDrawables.size();
-        for (int i = 0; i < length; i++) {
-            TargetDrawable target = mTargetDrawables.get(i);
-            target.setState(TargetDrawable.STATE_INACTIVE);
-            mTargetAnimations.add(Tweener.to(target, duration,
-                    "ease", Ease.Cubic.easeOut,
-                    "alpha", 0.0f,
-                    "scaleX", targetScale,
-                    "scaleY", targetScale,
-                    "delay", delay,
-                    "onUpdate", mUpdateListener));
-        }
-
-        final float ringScaleTarget = expanded ? RING_SCALE_EXPANDED : RING_SCALE_COLLAPSED;
-        mTargetAnimations.add(Tweener.to(mOuterRing, duration,
-                "ease", Ease.Cubic.easeOut,
-                "alpha", 0.0f,
-                "scaleX", ringScaleTarget,
-                "scaleY", ringScaleTarget,
-                "delay", delay,
-                "onUpdate", mUpdateListener,
-                "onComplete", mTargetUpdateListener));
-
-        mTargetAnimations.start();
-    }
-
-    private void showTargets(boolean animate) {
-        mTargetAnimations.stop();
-        mAnimatingTargets = animate;
-        final int delay = animate ? SHOW_ANIMATION_DELAY : 0;
-        final int duration = animate ? SHOW_ANIMATION_DURATION : 0;
-        final int length = mTargetDrawables.size();
-        for (int i = 0; i < length; i++) {
-            TargetDrawable target = mTargetDrawables.get(i);
-            target.setState(TargetDrawable.STATE_INACTIVE);
-            mTargetAnimations.add(Tweener.to(target, duration,
-                    "ease", Ease.Cubic.easeOut,
-                    "alpha", 1.0f,
-                    "scaleX", 1.0f,
-                    "scaleY", 1.0f,
-                    "delay", delay,
-                    "onUpdate", mUpdateListener));
-        }
-        mTargetAnimations.add(Tweener.to(mOuterRing, duration,
-                "ease", Ease.Cubic.easeOut,
-                "alpha", 1.0f,
-                "scaleX", 1.0f,
-                "scaleY", 1.0f,
-                "delay", delay,
-                "onUpdate", mUpdateListener,
-                "onComplete", mTargetUpdateListener));
-
-        mTargetAnimations.start();
-    }
-
-    private void vibrate() {
-        final boolean hapticEnabled = Settings.System.getIntForUser(
-                mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 1,
-                UserHandle.USER_CURRENT) != 0;
-        if (mVibrator != null && hapticEnabled) {
-            mVibrator.vibrate(mVibrationDuration, AudioManager.STREAM_SYSTEM);
-        }
-    }
-
-    private ArrayList<TargetDrawable> loadDrawableArray(int resourceId) {
-        Resources res = getContext().getResources();
-        TypedArray array = res.obtainTypedArray(resourceId);
-        final int count = array.length();
-        ArrayList<TargetDrawable> drawables = new ArrayList<TargetDrawable>(count);
-        for (int i = 0; i < count; i++) {
-            TypedValue value = array.peekValue(i);
-            TargetDrawable target = new TargetDrawable(res, value != null ? value.resourceId : 0);
-            drawables.add(target);
-        }
-        array.recycle();
-        return drawables;
-    }
-
-    private void internalSetTargetResources(int resourceId) {
-        mTargetDrawables = loadDrawableArray(resourceId);
-        mTargetResourceId = resourceId;
-        final int count = mTargetDrawables.size();
-        int maxWidth = mHandleDrawable.getWidth();
-        int maxHeight = mHandleDrawable.getHeight();
-        for (int i = 0; i < count; i++) {
-            TargetDrawable target = mTargetDrawables.get(i);
-            maxWidth = Math.max(maxWidth, target.getWidth());
-            maxHeight = Math.max(maxHeight, target.getHeight());
-        }
-        if (mMaxTargetWidth != maxWidth || mMaxTargetHeight != maxHeight) {
-            mMaxTargetWidth = maxWidth;
-            mMaxTargetHeight = maxHeight;
-            requestLayout(); // required to resize layout and call updateTargetPositions()
-        } else {
-            updateTargetPositions(mWaveCenterX, mWaveCenterY);
-            updateChevronPositions(mWaveCenterX, mWaveCenterY);
-        }
-    }
-
-    /**
-     * Loads an array of drawables from the given resourceId.
-     *
-     * @param resourceId
-     */
-    public void setTargetResources(int resourceId) {
-        if (mAnimatingTargets) {
-            // postpone this change until we return to the initial state
-            mNewTargetResources = resourceId;
-        } else {
-            internalSetTargetResources(resourceId);
-        }
-    }
-
-    public int getTargetResourceId() {
-        return mTargetResourceId;
-    }
-
-    /**
-     * Sets the resource id specifying the target descriptions for accessibility.
-     *
-     * @param resourceId The resource id.
-     */
-    public void setTargetDescriptionsResourceId(int resourceId) {
-        mTargetDescriptionsResourceId = resourceId;
-        if (mTargetDescriptions != null) {
-            mTargetDescriptions.clear();
-        }
-    }
-
-    /**
-     * Gets the resource id specifying the target descriptions for accessibility.
-     *
-     * @return The resource id.
-     */
-    public int getTargetDescriptionsResourceId() {
-        return mTargetDescriptionsResourceId;
-    }
-
-    /**
-     * Sets the resource id specifying the target direction descriptions for accessibility.
-     *
-     * @param resourceId The resource id.
-     */
-    public void setDirectionDescriptionsResourceId(int resourceId) {
-        mDirectionDescriptionsResourceId = resourceId;
-        if (mDirectionDescriptions != null) {
-            mDirectionDescriptions.clear();
-        }
-    }
-
-    /**
-     * Gets the resource id specifying the target direction descriptions.
-     *
-     * @return The resource id.
-     */
-    public int getDirectionDescriptionsResourceId() {
-        return mDirectionDescriptionsResourceId;
-    }
-
-    /**
-     * Enable or disable vibrate on touch.
-     *
-     * @param enabled
-     */
-    public void setVibrateEnabled(boolean enabled) {
-        if (enabled && mVibrator == null) {
-            mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
-        } else {
-            mVibrator = null;
-        }
-    }
-
-    /**
-     * Starts chevron animation. Example use case: show chevron animation whenever the phone rings
-     * or the user touches the screen.
-     *
-     */
-    public void ping() {
-        startChevronAnimation();
-    }
-
-    /**
-     * Resets the widget to default state and cancels all animation. If animate is 'true', will
-     * animate objects into place. Otherwise, objects will snap back to place.
-     *
-     * @param animate
-     */
-    public void reset(boolean animate) {
-        mChevronAnimations.stop();
-        mHandleAnimations.stop();
-        mTargetAnimations.stop();
-        startBackgroundAnimation(0, 0.0f);
-        hideChevrons();
-        hideTargets(animate, false);
-        deactivateHandle(0, 0, 1.0f, null);
-        Tweener.reset();
-    }
-
-    private void startBackgroundAnimation(int duration, float alpha) {
-        Drawable background = getBackground();
-        if (mAlwaysTrackFinger && background != null) {
-            if (mBackgroundAnimator != null) {
-                mBackgroundAnimator.animator.end();
-            }
-            mBackgroundAnimator = Tweener.to(background, duration,
-                    "ease", Ease.Cubic.easeIn,
-                    "alpha", new int[] {0, (int)(255.0f * alpha)},
-                    "delay", SHOW_ANIMATION_DELAY);
-            mBackgroundAnimator.animator.start();
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        final int action = event.getAction();
-        boolean handled = false;
-        switch (action) {
-            case MotionEvent.ACTION_DOWN:
-                if (DEBUG) Log.v(TAG, "*** DOWN ***");
-                handleDown(event);
-                handled = true;
-                break;
-
-            case MotionEvent.ACTION_MOVE:
-                if (DEBUG) Log.v(TAG, "*** MOVE ***");
-                handleMove(event);
-                handled = true;
-                break;
-
-            case MotionEvent.ACTION_UP:
-                if (DEBUG) Log.v(TAG, "*** UP ***");
-                handleMove(event);
-                handleUp(event);
-                handled = true;
-                break;
-
-            case MotionEvent.ACTION_CANCEL:
-                if (DEBUG) Log.v(TAG, "*** CANCEL ***");
-                handleMove(event);
-                handleCancel(event);
-                handled = true;
-                break;
-        }
-        invalidate();
-        return handled ? true : super.onTouchEvent(event);
-    }
-
-    private void moveHandleTo(float x, float y, boolean animate) {
-        mHandleDrawable.setX(x);
-        mHandleDrawable.setY(y);
-    }
-
-    private void handleDown(MotionEvent event) {
-        float eventX = event.getX();
-        float eventY = event.getY();
-        switchToState(STATE_START, eventX, eventY);
-        if (!trySwitchToFirstTouchState(eventX, eventY)) {
-            mDragging = false;
-            ping();
-        }
-    }
-
-    private void handleUp(MotionEvent event) {
-        if (DEBUG && mDragging) Log.v(TAG, "** Handle RELEASE");
-        switchToState(STATE_FINISH, event.getX(), event.getY());
-    }
-
-    private void handleCancel(MotionEvent event) {
-        if (DEBUG && mDragging) Log.v(TAG, "** Handle CANCEL");
-
-        // We should drop the active target here but it interferes with
-        // moving off the screen in the direction of the navigation bar. At some point we may
-        // want to revisit how we handle this. For now we'll allow a canceled event to
-        // activate the current target.
-
-        // mActiveTarget = -1; // Drop the active target if canceled.
-
-        switchToState(STATE_FINISH, event.getX(), event.getY());
-    }
-
-    private void handleMove(MotionEvent event) {
-        int activeTarget = -1;
-        final int historySize = event.getHistorySize();
-        ArrayList<TargetDrawable> targets = mTargetDrawables;
-        int ntargets = targets.size();
-        float x = 0.0f;
-        float y = 0.0f;
-        for (int k = 0; k < historySize + 1; k++) {
-            float eventX = k < historySize ? event.getHistoricalX(k) : event.getX();
-            float eventY = k < historySize ? event.getHistoricalY(k) : event.getY();
-            // tx and ty are relative to wave center
-            float tx = eventX - mWaveCenterX;
-            float ty = eventY - mWaveCenterY;
-            float touchRadius = (float) Math.sqrt(dist2(tx, ty));
-            final float scale = touchRadius > mOuterRadius ? mOuterRadius / touchRadius : 1.0f;
-            float limitX = tx * scale;
-            float limitY = ty * scale;
-            double angleRad = Math.atan2(-ty, tx);
-
-            if (!mDragging) {
-                trySwitchToFirstTouchState(eventX, eventY);
-            }
-
-            if (mDragging) {
-                // For multiple targets, snap to the one that matches
-                final float snapRadius = mOuterRadius - mSnapMargin;
-                final float snapDistance2 = snapRadius * snapRadius;
-                // Find first target in range
-                for (int i = 0; i < ntargets; i++) {
-                    TargetDrawable target = targets.get(i);
-
-                    double targetMinRad = (i - 0.5) * 2 * Math.PI / ntargets;
-                    double targetMaxRad = (i + 0.5) * 2 * Math.PI / ntargets;
-                    if (target.isEnabled()) {
-                        boolean angleMatches =
-                            (angleRad > targetMinRad && angleRad <= targetMaxRad) ||
-                            (angleRad + 2 * Math.PI > targetMinRad &&
-                             angleRad + 2 * Math.PI <= targetMaxRad);
-                        if (angleMatches && (dist2(tx, ty) > snapDistance2)) {
-                            activeTarget = i;
-                        }
-                    }
-                }
-            }
-            x = limitX;
-            y = limitY;
-        }
-
-        if (!mDragging) {
-            return;
-        }
-
-        if (activeTarget != -1) {
-            switchToState(STATE_SNAP, x,y);
-            moveHandleTo(x, y, false);
-        } else {
-            switchToState(STATE_TRACKING, x, y);
-            moveHandleTo(x, y, false);
-        }
-
-        // Draw handle outside parent's bounds
-        invalidateGlobalRegion(mHandleDrawable);
-
-        if (mActiveTarget != activeTarget) {
-            // Defocus the old target
-            if (mActiveTarget != -1) {
-                TargetDrawable target = targets.get(mActiveTarget);
-                if (target.hasState(TargetDrawable.STATE_FOCUSED)) {
-                    target.setState(TargetDrawable.STATE_INACTIVE);
-                }
-            }
-            // Focus the new target
-            if (activeTarget != -1) {
-                TargetDrawable target = targets.get(activeTarget);
-                if (target.hasState(TargetDrawable.STATE_FOCUSED)) {
-                    target.setState(TargetDrawable.STATE_FOCUSED);
-                }
-                if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                    String targetContentDescription = getTargetDescription(activeTarget);
-                    announceText(targetContentDescription);
-                }
-                activateHandle(0, 0, 0.0f, null);
-            } else {
-                activateHandle(0, 0, 1.0f, null);
-            }
-        }
-        mActiveTarget = activeTarget;
-    }
-
-    @Override
-    public boolean onHoverEvent(MotionEvent event) {
-        if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) {
-            final int action = event.getAction();
-            switch (action) {
-                case MotionEvent.ACTION_HOVER_ENTER:
-                    event.setAction(MotionEvent.ACTION_DOWN);
-                    break;
-                case MotionEvent.ACTION_HOVER_MOVE:
-                    event.setAction(MotionEvent.ACTION_MOVE);
-                    break;
-                case MotionEvent.ACTION_HOVER_EXIT:
-                    event.setAction(MotionEvent.ACTION_UP);
-                    break;
-            }
-            onTouchEvent(event);
-            event.setAction(action);
-        }
-        return super.onHoverEvent(event);
-    }
-
-    /**
-     * Sets the current grabbed state, and dispatches a grabbed state change
-     * event to our listener.
-     */
-    private void setGrabbedState(int newState) {
-        if (newState != mGrabbedState) {
-            if (newState != OnTriggerListener.NO_HANDLE) {
-                vibrate();
-            }
-            mGrabbedState = newState;
-            if (mOnTriggerListener != null) {
-                if (newState == OnTriggerListener.NO_HANDLE) {
-                    mOnTriggerListener.onReleased(this, OnTriggerListener.CENTER_HANDLE);
-                } else {
-                    mOnTriggerListener.onGrabbed(this, OnTriggerListener.CENTER_HANDLE);
-                }
-                mOnTriggerListener.onGrabbedStateChange(this, newState);
-            }
-        }
-    }
-
-    private boolean trySwitchToFirstTouchState(float x, float y) {
-        final float tx = x - mWaveCenterX;
-        final float ty = y - mWaveCenterY;
-        if (mAlwaysTrackFinger || dist2(tx,ty) <= getScaledTapRadiusSquared()) {
-            if (DEBUG) Log.v(TAG, "** Handle HIT");
-            switchToState(STATE_FIRST_TOUCH, x, y);
-            moveHandleTo(tx, ty, false);
-            mDragging = true;
-            return true;
-        }
-        return false;
-    }
-
-    private void assignDefaultsIfNeeded() {
-        if (mOuterRadius == 0.0f) {
-            mOuterRadius = Math.max(mOuterRing.getWidth(), mOuterRing.getHeight())/2.0f;
-        }
-        if (mSnapMargin == 0.0f) {
-            mSnapMargin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                    SNAP_MARGIN_DEFAULT, getContext().getResources().getDisplayMetrics());
-        }
-    }
-
-    private void computeInsets(int dx, int dy) {
-        final int layoutDirection = getLayoutDirection();
-        final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
-
-        switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
-            case Gravity.LEFT:
-                mHorizontalInset = 0;
-                break;
-            case Gravity.RIGHT:
-                mHorizontalInset = dx;
-                break;
-            case Gravity.CENTER_HORIZONTAL:
-            default:
-                mHorizontalInset = dx / 2;
-                break;
-        }
-        switch (absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK) {
-            case Gravity.TOP:
-                mVerticalInset = 0;
-                break;
-            case Gravity.BOTTOM:
-                mVerticalInset = dy;
-                break;
-            case Gravity.CENTER_VERTICAL:
-            default:
-                mVerticalInset = dy / 2;
-                break;
-        }
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        final int width = right - left;
-        final int height = bottom - top;
-
-        // Target placement width/height. This puts the targets on the greater of the ring
-        // width or the specified outer radius.
-        final float placementWidth = Math.max(mOuterRing.getWidth(), 2 * mOuterRadius);
-        final float placementHeight = Math.max(mOuterRing.getHeight(), 2 * mOuterRadius);
-        float newWaveCenterX = mHorizontalInset
-                + Math.max(width, mMaxTargetWidth + placementWidth) / 2;
-        float newWaveCenterY = mVerticalInset
-                + Math.max(height, + mMaxTargetHeight + placementHeight) / 2;
-
-        if (mInitialLayout) {
-            hideChevrons();
-            hideTargets(false, false);
-            moveHandleTo(0, 0, false);
-            mInitialLayout = false;
-        }
-
-        mOuterRing.setPositionX(newWaveCenterX);
-        mOuterRing.setPositionY(newWaveCenterY);
-
-        mHandleDrawable.setPositionX(newWaveCenterX);
-        mHandleDrawable.setPositionY(newWaveCenterY);
-
-        updateTargetPositions(newWaveCenterX, newWaveCenterY);
-        updateChevronPositions(newWaveCenterX, newWaveCenterY);
-
-        mWaveCenterX = newWaveCenterX;
-        mWaveCenterY = newWaveCenterY;
-
-        if (DEBUG) dump();
-    }
-
-    private void updateTargetPositions(float centerX, float centerY) {
-        // Reposition the target drawables if the view changed.
-        ArrayList<TargetDrawable> targets = mTargetDrawables;
-        final int size = targets.size();
-        final float alpha = (float) (-2.0f * Math.PI / size);
-        for (int i = 0; i < size; i++) {
-            final TargetDrawable targetIcon = targets.get(i);
-            final float angle = alpha * i;
-            targetIcon.setPositionX(centerX);
-            targetIcon.setPositionY(centerY);
-            targetIcon.setX(mOuterRadius * (float) Math.cos(angle));
-            targetIcon.setY(mOuterRadius * (float) Math.sin(angle));
-        }
-    }
-
-    private void updateChevronPositions(float centerX, float centerY) {
-        ArrayList<TargetDrawable> chevrons = mChevronDrawables;
-        final int size = chevrons.size();
-        for (int i = 0; i < size; i++) {
-            TargetDrawable target = chevrons.get(i);
-            if (target != null) {
-                target.setPositionX(centerX);
-                target.setPositionY(centerY);
-            }
-        }
-    }
-
-    private void hideChevrons() {
-        ArrayList<TargetDrawable> chevrons = mChevronDrawables;
-        final int size = chevrons.size();
-        for (int i = 0; i < size; i++) {
-            TargetDrawable chevron = chevrons.get(i);
-            if (chevron != null) {
-                chevron.setAlpha(0.0f);
-            }
-        }
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        mOuterRing.draw(canvas);
-        final int ntargets = mTargetDrawables.size();
-        for (int i = 0; i < ntargets; i++) {
-            TargetDrawable target = mTargetDrawables.get(i);
-            if (target != null) {
-                target.draw(canvas);
-            }
-        }
-        final int nchevrons = mChevronDrawables.size();
-        for (int i = 0; i < nchevrons; i++) {
-            TargetDrawable chevron = mChevronDrawables.get(i);
-            if (chevron != null) {
-                chevron.draw(canvas);
-            }
-        }
-        mHandleDrawable.draw(canvas);
-    }
-
-    public void setOnTriggerListener(OnTriggerListener listener) {
-        mOnTriggerListener = listener;
-    }
-
-    private float square(float d) {
-        return d * d;
-    }
-
-    private float dist2(float dx, float dy) {
-        return dx*dx + dy*dy;
-    }
-
-    private float getScaledTapRadiusSquared() {
-        final float scaledTapRadius;
-        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-            scaledTapRadius = TAP_RADIUS_SCALE_ACCESSIBILITY_ENABLED * mTapRadius;
-        } else {
-            scaledTapRadius = mTapRadius;
-        }
-        return square(scaledTapRadius);
-    }
-
-    private void announceTargets() {
-        StringBuilder utterance = new StringBuilder();
-        final int targetCount = mTargetDrawables.size();
-        for (int i = 0; i < targetCount; i++) {
-            String targetDescription = getTargetDescription(i);
-            String directionDescription = getDirectionDescription(i);
-            if (!TextUtils.isEmpty(targetDescription)
-                    && !TextUtils.isEmpty(directionDescription)) {
-                String text = String.format(directionDescription, targetDescription);
-                utterance.append(text);
-            }
-            if (utterance.length() > 0) {
-                announceText(utterance.toString());
-            }
-        }
-    }
-
-    private void announceText(String text) {
-        setContentDescription(text);
-        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
-        setContentDescription(null);
-    }
-
-    private String getTargetDescription(int index) {
-        if (mTargetDescriptions == null || mTargetDescriptions.isEmpty()) {
-            mTargetDescriptions = loadDescriptions(mTargetDescriptionsResourceId);
-            if (mTargetDrawables.size() != mTargetDescriptions.size()) {
-                Log.w(TAG, "The number of target drawables must be"
-                        + " euqal to the number of target descriptions.");
-                return null;
-            }
-        }
-        return mTargetDescriptions.get(index);
-    }
-
-    private String getDirectionDescription(int index) {
-        if (mDirectionDescriptions == null || mDirectionDescriptions.isEmpty()) {
-            mDirectionDescriptions = loadDescriptions(mDirectionDescriptionsResourceId);
-            if (mTargetDrawables.size() != mDirectionDescriptions.size()) {
-                Log.w(TAG, "The number of target drawables must be"
-                        + " euqal to the number of direction descriptions.");
-                return null;
-            }
-        }
-        return mDirectionDescriptions.get(index);
-    }
-
-    private ArrayList<String> loadDescriptions(int resourceId) {
-        TypedArray array = getContext().getResources().obtainTypedArray(resourceId);
-        final int count = array.length();
-        ArrayList<String> targetContentDescriptions = new ArrayList<String>(count);
-        for (int i = 0; i < count; i++) {
-            String contentDescription = array.getString(i);
-            targetContentDescriptions.add(contentDescription);
-        }
-        array.recycle();
-        return targetContentDescriptions;
-    }
-
-    public int getResourceIdForTarget(int index) {
-        final TargetDrawable drawable = mTargetDrawables.get(index);
-        return drawable == null ? 0 : drawable.getResourceId();
-    }
-
-    public void setEnableTarget(int resourceId, boolean enabled) {
-        for (int i = 0; i < mTargetDrawables.size(); i++) {
-            final TargetDrawable target = mTargetDrawables.get(i);
-            if (target.getResourceId() == resourceId) {
-                target.setEnabled(enabled);
-                break; // should never be more than one match
-            }
-        }
-    }
-
-    /**
-     * Gets the position of a target in the array that matches the given resource.
-     * @param resourceId
-     * @return the index or -1 if not found
-     */
-    public int getTargetPosition(int resourceId) {
-        for (int i = 0; i < mTargetDrawables.size(); i++) {
-            final TargetDrawable target = mTargetDrawables.get(i);
-            if (target.getResourceId() == resourceId) {
-                return i; // should never be more than one match
-            }
-        }
-        return -1;
-    }
-
-    private boolean replaceTargetDrawables(Resources res, int existingResourceId,
-            int newResourceId) {
-        if (existingResourceId == 0 || newResourceId == 0) {
-            return false;
-        }
-
-        boolean result = false;
-        final ArrayList<TargetDrawable> drawables = mTargetDrawables;
-        final int size = drawables.size();
-        for (int i = 0; i < size; i++) {
-            final TargetDrawable target = drawables.get(i);
-            if (target != null && target.getResourceId() == existingResourceId) {
-                target.setDrawable(res, newResourceId);
-                result = true;
-            }
-        }
-
-        if (result) {
-            requestLayout(); // in case any given drawable's size changes
-        }
-
-        return result;
-    }
-
-    /**
-     * Searches the given package for a resource to use to replace the Drawable on the
-     * target with the given resource id
-     * @param component of the .apk that contains the resource
-     * @param name of the metadata in the .apk
-     * @param existingResId the resource id of the target to search for
-     * @return true if found in the given package and replaced at least one target Drawables
-     */
-    public boolean replaceTargetDrawablesIfPresent(ComponentName component, String name,
-                int existingResId) {
-        if (existingResId == 0) return false;
-
-        try {
-            PackageManager packageManager = mContext.getPackageManager();
-            // Look for the search icon specified in the activity meta-data
-            Bundle metaData = packageManager.getActivityInfo(
-                    component, PackageManager.GET_META_DATA).metaData;
-            if (metaData != null) {
-                int iconResId = metaData.getInt(name);
-                if (iconResId != 0) {
-                    Resources res = packageManager.getResourcesForActivity(component);
-                    return replaceTargetDrawables(res, existingResId, iconResId);
-                }
-            }
-        } catch (NameNotFoundException e) {
-            Log.w(TAG, "Failed to swap drawable; "
-                    + component.flattenToShortString() + " not found", e);
-        } catch (Resources.NotFoundException nfe) {
-            Log.w(TAG, "Failed to swap drawable from "
-                    + component.flattenToShortString(), nfe);
-        }
-        return false;
-    }
-}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 51c5a86..711f28a 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -151,7 +151,8 @@
 	android_content_res_ObbScanner.cpp \
 	android_content_res_Configuration.cpp \
 	android_animation_PropertyValuesHolder.cpp \
-	com_android_internal_net_NetworkStatsFactory.cpp
+	com_android_internal_net_NetworkStatsFactory.cpp \
+	com_android_internal_os_Zygote.cpp
 
 LOCAL_C_INCLUDES += \
 	$(JNI_H_INCLUDE) \
@@ -177,7 +178,8 @@
 	external/harfbuzz_ng/src \
 	external/zlib \
 	frameworks/opt/emoji \
-	libcore/include
+	libcore/include \
+	$(call include-path-for, audio-utils) \
 
 LOCAL_SHARED_LIBRARIES := \
 	libmemtrack \
@@ -213,7 +215,8 @@
 	libjpeg \
 	libusbhost \
 	libharfbuzz_ng \
-	libz
+	libz \
+	libaudioutils \
 
 ifeq ($(USE_OPENGL_RENDERER),true)
 	LOCAL_SHARED_LIBRARIES += libhwui
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 9a7a5f9..6afeb86 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -178,6 +178,7 @@
 extern int register_android_animation_PropertyValuesHolder(JNIEnv *env);
 extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
 extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
+extern int register_com_android_internal_os_Zygote(JNIEnv *env);
 
 static AndroidRuntime* gCurRuntime = NULL;
 
@@ -1244,6 +1245,7 @@
     REG_JNI(register_android_net_TrafficStats),
     REG_JNI(register_android_os_MemoryFile),
     REG_JNI(register_com_android_internal_os_ZygoteInit),
+    REG_JNI(register_com_android_internal_os_Zygote),
     REG_JNI(register_android_hardware_Camera),
     REG_JNI(register_android_hardware_camera2_CameraMetadata),
     REG_JNI(register_android_hardware_SensorManager),
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 2b9a5c4..b89dced 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -7,6 +7,7 @@
 #include "SkImageDecoder.h"
 #include "SkImageRef_ashmem.h"
 #include "SkImageRef_GlobalPool.h"
+#include "SkMath.h"
 #include "SkPixelRef.h"
 #include "SkStream.h"
 #include "SkTemplates.h"
@@ -146,15 +147,15 @@
     return pr;
 }
 
-static SkBitmap::Config configForScaledOutput(SkBitmap::Config config) {
-    switch (config) {
-        case SkBitmap::kNo_Config:
-        case SkBitmap::kIndex8_Config:
-            return SkBitmap::kARGB_8888_Config;
+static SkColorType colorTypeForScaledOutput(SkColorType colorType) {
+    switch (colorType) {
+        case kUnknown_SkColorType:
+        case kIndex_8_SkColorType:
+            return kPMColor_SkColorType;
         default:
             break;
     }
-    return config;
+    return colorType;
 }
 
 class ScaleCheckingAllocator : public SkBitmap::HeapAllocator {
@@ -165,8 +166,8 @@
 
     virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
         // accounts for scale in final allocation, using eventual size and config
-        const int bytesPerPixel = SkBitmap::ComputeBytesPerPixel(
-                configForScaledOutput(bitmap->config()));
+        const int bytesPerPixel = SkColorTypeBytesPerPixel(
+                colorTypeForScaledOutput(bitmap->colorType()));
         const int requestedSize = bytesPerPixel *
                 int(bitmap->width() * mScale + 0.5f) *
                 int(bitmap->height() * mScale + 0.5f);
@@ -194,21 +195,28 @@
     }
 
     virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
-        if (!bitmap->getSize64().is32() || bitmap->getSize() > mSize) {
-            ALOGW("bitmap marked for reuse (%d bytes) can't fit new bitmap (%d bytes)",
-                    mSize, bitmap->getSize());
+        const SkImageInfo& info = bitmap->info();
+        if (info.fColorType == kUnknown_SkColorType) {
+            ALOGW("unable to reuse a bitmap as the target has an unknown bitmap configuration");
             return false;
         }
 
-        SkImageInfo bitmapInfo;
-        if (!bitmap->asImageInfo(&bitmapInfo)) {
-            ALOGW("unable to reuse a bitmap as the target has an unknown bitmap configuration");
+        const int64_t size64 = info.getSafeSize64(bitmap->rowBytes());
+        if (!sk_64_isS32(size64)) {
+            ALOGW("bitmap is too large");
+            return false;
+        }
+
+        const size_t size = sk_64_asS32(size64);
+        if (size > mSize) {
+            ALOGW("bitmap marked for reuse (%d bytes) can't fit new bitmap (%d bytes)",
+                    mSize, size);
             return false;
         }
 
         // Create a new pixelref with the new ctable that wraps the previous pixelref
         SkPixelRef* pr = new AndroidPixelRef(*static_cast<AndroidPixelRef*>(mPixelRef),
-                bitmapInfo, bitmap->rowBytes(), ctable);
+                info, bitmap->rowBytes(), ctable);
 
         bitmap->setPixelRef(pr)->unref();
         // since we're already allocated, we lockPixels right away
@@ -416,12 +424,12 @@
         const float sy = scaledHeight / float(decodingBitmap.height());
 
         // TODO: avoid copying when scaled size equals decodingBitmap size
-        SkBitmap::Config config = configForScaledOutput(decodingBitmap.config());
+        SkColorType colorType = colorTypeForScaledOutput(decodingBitmap.colorType());
         // FIXME: If the alphaType is kUnpremul and the image has alpha, the
         // colors may not be correct, since Skia does not yet support drawing
         // to/from unpremultiplied bitmaps.
-        outputBitmap->setConfig(config, scaledWidth, scaledHeight, 0,
-                                decodingBitmap.alphaType());
+        outputBitmap->setConfig(SkImageInfo::Make(scaledWidth, scaledHeight,
+                colorType, decodingBitmap.alphaType()));
         if (!outputBitmap->allocPixels(outputAllocator, NULL)) {
             return nullObjectReturn("allocation failed for scaled bitmap");
         }
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 7420055..946b898 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -680,9 +680,6 @@
             indices [ptCount * sizeof(uint16_t)]
         */
         ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[]
-#ifdef SK_SCALAR_IS_FIXED
-        storageSize += ptCount * sizeof(SkPoint);  // storage for verts
-#endif
         storageSize += indexCount * sizeof(uint16_t);  // indices[]
 
         SkAutoMalloc storage(storageSize);
@@ -693,16 +690,7 @@
         verts = (SkPoint*)(vertA.ptr() + vertIndex);
         indices = (uint16_t*)(texs + ptCount);
 #else
-        verts = texs + ptCount;
-        indices = (uint16_t*)(verts + ptCount);
-        // convert floats to fixed
-        {
-            const float* src = vertA.ptr() + vertIndex;
-            for (int i = 0; i < ptCount; i++) {
-                verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
-                src += 2;
-            }
-        }
+        SkASSERT(false);
 #endif
 
         // cons up texture coordinates and indices
@@ -804,25 +792,7 @@
             texs = (SkPoint*)(texA.ptr() + texIndex);
         }
 #else
-        int count = ptCount;    // for verts
-        if (jtexs != NULL) {
-            count += ptCount;   // += for texs
-        }
-        SkAutoMalloc storage(count * sizeof(SkPoint));
-        verts = (SkPoint*)storage.get();
-        const float* src = vertA.ptr() + vertIndex;
-        for (int i = 0; i < ptCount; i++) {
-            verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
-            src += 2;
-        }
-        if (jtexs != NULL) {
-            texs = verts + ptCount;
-            src = texA.ptr() + texIndex;
-            for (int i = 0; i < ptCount; i++) {
-                texs[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
-                src += 2;
-            }
-        }
+        SkASSERT(false);
 #endif
 
         const SkColor* colors = NULL;
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index 09589bd..a59ed19 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -50,14 +50,10 @@
         AutoJavaFloatArray autoArray(env, jarray, 20);
         const float* src = autoArray.ptr();
 
-#ifdef SK_SCALAR_IS_FIXED
-        SkFixed array[20];
-        for (int i = 0; i < 20; i++) {
-            array[i] = SkFloatToScalar(src[i]);
-        }
-        return reinterpret_cast<jlong>(new SkColorMatrixFilter(array));
-#else
+#ifdef SK_SCALAR_IS_FLOAT
         return reinterpret_cast<jlong>(new SkColorMatrixFilter(src));
+#else
+        SkASSERT(false);
 #endif
     }
 };
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 98edbdb..2883be9 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -6,6 +6,7 @@
 
 #include "SkCanvas.h"
 #include "SkDevice.h"
+#include "SkMath.h"
 #include "SkPicture.h"
 #include "SkRegion.h"
 #include <android_runtime/AndroidRuntime.h>
@@ -564,21 +565,20 @@
 
 jbyteArray GraphicsJNI::allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
                                              SkColorTable* ctable) {
-    Sk64 size64 = bitmap->getSize64();
-    if (size64.isNeg() || !size64.is32()) {
-        jniThrowException(env, "java/lang/IllegalArgumentException",
-                          "bitmap size exceeds 32bits");
+    const SkImageInfo& info = bitmap->info();
+    if (info.fColorType == kUnknown_SkColorType) {
+        doThrowIAE(env, "unknown bitmap configuration");
         return NULL;
     }
 
-    SkImageInfo bitmapInfo;
-    if (!bitmap->asImageInfo(&bitmapInfo)) {
-        jniThrowException(env, "java/lang/IllegalArgumentException",
-                "unknown bitmap configuration");
+    const int64_t size64 = info.getSafeSize64(bitmap->rowBytes());
+    if (!sk_64_isS32(size64)) {
+        doThrowIAE(env, "bitmap size exceeds 32bits");
         return NULL;
     }
+    const size_t size = sk_64_asS32(size64);
+    SkASSERT(size == info.getSafeSize(bitmap->rowBytes()));
 
-    size_t size = size64.get32();
     jbyteArray arrayObj = (jbyteArray) env->CallObjectMethod(gVMRuntime,
                                                              gVMRuntime_newNonMovableArray,
                                                              gByte_class, size);
@@ -591,7 +591,7 @@
         return NULL;
     }
     SkASSERT(addr);
-    SkPixelRef* pr = new AndroidPixelRef(env, bitmapInfo, (void*) addr,
+    SkPixelRef* pr = new AndroidPixelRef(env, info, (void*) addr,
             bitmap->rowBytes(), arrayObj, ctable);
     bitmap->setPixelRef(pr)->unref();
     // since we're already allocated, we lockPixels right away
diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp
index 6ae9fea..c400c57 100644
--- a/core/jni/android/graphics/Matrix.cpp
+++ b/core/jni/android/graphics/Matrix.cpp
@@ -272,18 +272,11 @@
         float* dst = autoDst.ptr() + dstIndex;
         bool result;
 
-#ifdef SK_SCALAR_IS_FIXED        
-        SkPoint srcPt[4], dstPt[4];
-        for (int i = 0; i < ptCount; i++) {
-            int x = i << 1;
-            int y = x + 1;
-            srcPt[i].set(SkFloatToScalar(src[x]), SkFloatToScalar(src[y]));
-            dstPt[i].set(SkFloatToScalar(dst[x]), SkFloatToScalar(dst[y]));
-        }
-        result = matrix->setPolyToPoly(srcPt, dstPt, ptCount);
-#else
+#ifdef SK_SCALAR_IS_FLOAT
         result = matrix->setPolyToPoly((const SkPoint*)src, (const SkPoint*)dst,
                                      ptCount);
+#else
+        SkASSERT(false);
 #endif
         return result ? JNI_TRUE : JNI_FALSE;
     }
@@ -304,36 +297,15 @@
         AutoJavaFloatArray autoDst(env, dst, dstIndex + (ptCount << 1), kRW_JNIAccess);
         float* srcArray = autoSrc.ptr() + srcIndex;
         float* dstArray = autoDst.ptr() + dstIndex;
-        
-#ifdef SK_SCALAR_IS_FIXED        
-        // we allocate twice the count, 1 set for src, 1 for dst
-        SkAutoSTMalloc<32, SkPoint> storage(ptCount * 2);
-        SkPoint* pts = storage.get();
-        SkPoint* srcPt = pts;
-        SkPoint* dstPt = pts + ptCount;
-        
-        int i;
-        for (i = 0; i < ptCount; i++) {
-            srcPt[i].set(SkFloatToScalar(srcArray[i << 1]),
-                         SkFloatToScalar(srcArray[(i << 1) + 1]));
-        }
-        
-        if (isPts)
-            matrix->mapPoints(dstPt, srcPt, ptCount);
-        else
-            matrix->mapVectors(dstPt, srcPt, ptCount);
-        
-        for (i = 0; i < ptCount; i++) {
-            dstArray[i << 1]  = SkScalarToFloat(dstPt[i].fX);
-            dstArray[(i << 1) + 1]  = SkScalarToFloat(dstPt[i].fY);
-        }
-#else
+#ifdef SK_SCALAR_IS_FLOAT
         if (isPts)
             matrix->mapPoints((SkPoint*)dstArray, (const SkPoint*)srcArray,
                               ptCount);
         else
             matrix->mapVectors((SkVector*)dstArray, (const SkVector*)srcArray,
                                ptCount);
+#else
+        SkASSERT(false);
 #endif
     }
 
@@ -356,18 +328,12 @@
         SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
         AutoJavaFloatArray autoValues(env, values, 9, kRW_JNIAccess);
         float* dst = autoValues.ptr();
-
-#ifdef SK_SCALAR_IS_FIXED
-        for (int i = 0; i < 6; i++) {
-            dst[i] = SkFixedToFloat(matrix->get(i));
-        }
-        for (int j = 6; j < 9; j++) {
-            dst[j] = SkFractToFloat(matrix->get(j));
-        }
-#else
+#ifdef SK_SCALAR_IS_FLOAT
         for (int i = 0; i < 9; i++) {
             dst[i] = matrix->get(i);
         }
+#else
+        SkASSERT(false);
 #endif
     }
 
@@ -376,17 +342,12 @@
         AutoJavaFloatArray autoValues(env, values, 9, kRO_JNIAccess);
         const float* src = autoValues.ptr();
 
-#ifdef SK_SCALAR_IS_FIXED
-        for (int i = 0; i < 6; i++) {
-            matrix->set(i, SkFloatToFixed(src[i]));
-        }
-        for (int j = 6; j < 9; j++) {
-            matrix->set(j, SkFloatToFract(src[j]));
-        }
-#else
+#ifdef SK_SCALAR_IS_FLOAT
         for (int i = 0; i < 9; i++) {
             matrix->set(i, src[i]);
         }
+#else
+        SkASSERT(false);
 #endif
     }
 
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 51990d5..1167bfe 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -422,16 +422,16 @@
         SkPaint::FontMetrics metrics;
 
         GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics);
-        int ascent = SkScalarRound(metrics.fAscent);
-        int descent = SkScalarRound(metrics.fDescent);
-        int leading = SkScalarRound(metrics.fLeading);
+        int ascent = SkScalarRoundToInt(metrics.fAscent);
+        int descent = SkScalarRoundToInt(metrics.fDescent);
+        int leading = SkScalarRoundToInt(metrics.fLeading);
 
         if (metricsObj) {
             SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class));
-            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloor(metrics.fTop));
+            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloorToInt(metrics.fTop));
             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent);
             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent);
-            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeil(metrics.fBottom));
+            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeilToInt(metrics.fBottom));
             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading);
         }
         return descent - ascent + leading;
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 5db083a..9279758 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -492,7 +492,7 @@
     (((ucs) & 0xfc00) == 0xdc00)
 
 #ifndef HB_SurrogateToUcs4
-#define HB_SurrogateToUcs4_(high, low) \
+#define HB_SurrogateToUcs4(high, low) \
     (((hb_codepoint_t)(high))<<10) + (low) - 0x35fdc00;
 #endif
 
@@ -784,7 +784,7 @@
     if (typeface) {
         currentStyle = typeface->style();
     }
-    typeface = SkCreateTypefaceForScriptNG(script, currentStyle);
+    typeface = SkCreateTypefaceForScript(script, currentStyle);
 #if DEBUG_GLYPHS
     ALOGD("Using Harfbuzz Script %c%c%c%c, Style %d", HB_UNTAG(script), currentStyle);
 #endif
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 58b61ba..307293f 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -230,7 +230,7 @@
         ssize_t offset;
         size_t size;
         sp<IMemoryHeap> heap = dataPtr->getMemory(&offset, &size);
-        ALOGV("copyAndPost: off=%ld, size=%d", offset, size);
+        ALOGV("copyAndPost: off=%zd, size=%zu", offset, size);
         uint8_t *heapBase = (uint8_t*)heap->base();
 
         if (heapBase != NULL) {
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 0132b5f..d8faaf3 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -166,7 +166,7 @@
         ALOGE("Error creating AudioRecord: channel mask %#x is not valid.", channelMask);
         return (jint) AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
     }
-    uint32_t nbChannels = popcount(channelMask);
+    uint32_t channelCount = popcount(channelMask);
 
     // compare the format against the Java constants
     audio_format_t format = audioFormatToNative(audioFormat);
@@ -181,7 +181,7 @@
          ALOGE("Error creating AudioRecord: frameCount is 0.");
         return (jint) AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
     }
-    size_t frameSize = nbChannels * bytesPerSample;
+    size_t frameSize = channelCount * bytesPerSample;
     size_t frameCount = buffSizeInBytes / frameSize;
 
     if ((uint32_t(source) >= AUDIO_SOURCE_CNT) && (uint32_t(source) != AUDIO_SOURCE_HOTWORD)) {
@@ -220,7 +220,7 @@
     lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
     lpCallbackData->busy = false;
 
-    lpRecorder->set((audio_source_t) source,
+    const status_t status = lpRecorder->set((audio_source_t) source,
         sampleRateInHertz,
         format,        // word length, PCM
         channelMask,
@@ -231,7 +231,6 @@
         true,          // threadCanCallJava
         sessionId);
 
-    const status_t status = lpRecorder->initCheck();
     if (status != NO_ERROR) {
         ALOGE("Error creating AudioRecord instance: initialization check failed with status %d.",
                 status);
@@ -312,7 +311,7 @@
     if (lpRecorder == NULL) {
         return;
     }
-    ALOGV("About to delete lpRecorder: %" PRIxPTR "\n", lpRecorder.get());
+    ALOGV("About to delete lpRecorder: %p", lpRecorder.get());
     lpRecorder->stop();
 
     audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetLongField(
@@ -325,7 +324,7 @@
     // delete the callback information
     if (lpCookie) {
         Mutex::Autolock l(sLock);
-        ALOGV("deleting lpCookie: %" PRIxPTR "\n", lpCookie);
+        ALOGV("deleting lpCookie: %p", lpCookie);
         while (lpCookie->busy) {
             if (lpCookie->cond.waitRelative(sLock,
                                             milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
@@ -501,17 +500,17 @@
 // returns 0 if the parameter combination is not supported.
 // return -1 if there was an error querying the buffer size.
 static jint android_media_AudioRecord_get_min_buff_size(JNIEnv *env,  jobject thiz,
-    jint sampleRateInHertz, jint nbChannels, jint audioFormat) {
+    jint sampleRateInHertz, jint channelCount, jint audioFormat) {
 
     ALOGV(">> android_media_AudioRecord_get_min_buff_size(%d, %d, %d)",
-          sampleRateInHertz, nbChannels, audioFormat);
+          sampleRateInHertz, channelCount, audioFormat);
 
     size_t frameCount = 0;
     audio_format_t format = audioFormatToNative(audioFormat);
     status_t result = AudioRecord::getMinFrameCount(&frameCount,
             sampleRateInHertz,
             format,
-            audio_channel_in_mask_from_count(nbChannels));
+            audio_channel_in_mask_from_count(channelCount));
 
     if (result == BAD_VALUE) {
         return 0;
@@ -519,7 +518,7 @@
     if (result != NO_ERROR) {
         return -1;
     }
-    return frameCount * nbChannels * audio_bytes_per_sample(format);
+    return frameCount * channelCount * audio_bytes_per_sample(format);
 }
 
 
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 3a5b566..162d0c4 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -26,6 +26,7 @@
 #include <utils/Log.h>
 #include <media/AudioSystem.h>
 #include <media/AudioTrack.h>
+#include <audio_utils/primitives.h>
 
 #include <binder/MemoryHeapBase.h>
 #include <binder/MemoryBase.h>
@@ -203,25 +204,30 @@
     uint32_t afSampleRate;
     size_t afFrameCount;
 
-    if (AudioSystem::getOutputFrameCount(&afFrameCount, (audio_stream_type_t) streamType) != NO_ERROR) {
-        ALOGE("Error creating AudioTrack: Could not get AudioSystem frame count.");
+    status_t status = AudioSystem::getOutputFrameCount(&afFrameCount,
+            (audio_stream_type_t) streamType);
+    if (status != NO_ERROR) {
+        ALOGE("Error %d creating AudioTrack: Could not get AudioSystem frame count "
+              "for stream type %d.", status, streamType);
         return (jint) AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
     }
-    if (AudioSystem::getOutputSamplingRate(&afSampleRate, (audio_stream_type_t) streamType) != NO_ERROR) {
-        ALOGE("Error creating AudioTrack: Could not get AudioSystem sampling rate.");
+    status = AudioSystem::getOutputSamplingRate(&afSampleRate, (audio_stream_type_t) streamType);
+    if (status != NO_ERROR) {
+        ALOGE("Error %d creating AudioTrack: Could not get AudioSystem sampling rate "
+              "for stream type %d.", status, streamType);
         return (jint) AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
     }
 
     // Java channel masks don't map directly to the native definition, but it's a simple shift
     // to skip the two deprecated channel configurations "default" and "mono".
-    uint32_t nativeChannelMask = ((uint32_t)javaChannelMask) >> 2;
+    audio_channel_mask_t nativeChannelMask = ((uint32_t)javaChannelMask) >> 2;
 
     if (!audio_is_output_channel(nativeChannelMask)) {
         ALOGE("Error creating AudioTrack: invalid channel mask %#x.", javaChannelMask);
         return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
     }
 
-    int nbChannels = popcount(nativeChannelMask);
+    uint32_t channelCount = popcount(nativeChannelMask);
 
     // check the stream type
     audio_stream_type_t atStreamType;
@@ -237,7 +243,7 @@
         atStreamType = (audio_stream_type_t) streamType;
         break;
     default:
-        ALOGE("Error creating AudioTrack: unknown stream type.");
+        ALOGE("Error creating AudioTrack: unknown stream type %d.", streamType);
         return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE;
     }
 
@@ -245,8 +251,7 @@
     // This function was called from Java, so we compare the format against the Java constants
     audio_format_t format = audioFormatToNative(audioFormat);
     if (format == AUDIO_FORMAT_INVALID) {
-
-        ALOGE("Error creating AudioTrack: unsupported audio format.");
+        ALOGE("Error creating AudioTrack: unsupported audio format %d.", audioFormat);
         return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
     }
 
@@ -265,7 +270,7 @@
 
     // compute the frame count
     const size_t bytesPerSample = audio_bytes_per_sample(format);
-    size_t frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
+    size_t frameCount = buffSizeInBytes / (channelCount * bytesPerSample);
 
     jclass clazz = env->GetObjectClass(thiz);
     if (clazz == NULL) {
@@ -303,7 +308,7 @@
     switch (memoryMode) {
     case MODE_STREAM:
 
-        lpTrack->set(
+        status = lpTrack->set(
             atStreamType,// stream type
             sampleRateInHertz,
             format,// word length, PCM
@@ -325,7 +330,7 @@
             goto native_init_failure;
         }
 
-        lpTrack->set(
+        status = lpTrack->set(
             atStreamType,// stream type
             sampleRateInHertz,
             format,// word length, PCM
@@ -344,8 +349,8 @@
         goto native_init_failure;
     }
 
-    if (lpTrack->initCheck() != NO_ERROR) {
-        ALOGE("Error initializing AudioTrack");
+    if (status != NO_ERROR) {
+        ALOGE("Error %d initializing AudioTrack", status);
         goto native_init_failure;
     }
 
@@ -546,10 +551,8 @@
             }
             int count = sizeInBytes;
             int16_t *dst = (int16_t *)track->sharedBuffer()->pointer();
-            const int8_t *src = (const int8_t *)(data + offsetInBytes);
-            while (count--) {
-                *dst++ = (int16_t)(*src++^0x80) << 8;
-            }
+            const uint8_t *src = (const uint8_t *)(data + offsetInBytes);
+            memcpy_to_i16_from_u8(dst, src, count);
             // even though we wrote 2*sizeInBytes, we only report sizeInBytes as written to hide
             // the 8bit mixer restriction from the user of this function
             written = sizeInBytes;
@@ -853,9 +856,10 @@
         break;
     }
 
-    if (AudioSystem::getOutputSamplingRate(&afSamplingRate, nativeStreamType) != NO_ERROR) {
-        ALOGE("AudioSystem::getOutputSamplingRate() for stream type %d failed in AudioTrack JNI",
-            nativeStreamType);
+    status_t status = AudioSystem::getOutputSamplingRate(&afSamplingRate, nativeStreamType);
+    if (status != NO_ERROR) {
+        ALOGE("Error %d in AudioSystem::getOutputSamplingRate() for stream type %d "
+              "in AudioTrack JNI", status, nativeStreamType);
         return DEFAULT_OUTPUT_SAMPLE_RATE;
     } else {
         return afSamplingRate;
@@ -867,7 +871,7 @@
 // returns the minimum required size for the successful creation of a streaming AudioTrack
 // returns -1 if there was an error querying the hardware.
 static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env,  jobject thiz,
-    jint sampleRateInHertz, jint nbChannels, jint audioFormat) {
+    jint sampleRateInHertz, jint channelCount, jint audioFormat) {
 
     size_t frameCount;
     const status_t status = AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT,
@@ -879,21 +883,26 @@
     }
     const audio_format_t format = audioFormatToNative(audioFormat);
     const size_t bytesPerSample = audio_bytes_per_sample(format);
-    return frameCount * nbChannels * bytesPerSample;
+    return frameCount * channelCount * bytesPerSample;
 }
 
 // ----------------------------------------------------------------------------
-static void
+static jint
 android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )
 {
     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
     if (lpTrack == NULL ) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");
-        return;
+        return -1;
     }
 
-    lpTrack->setAuxEffectSendLevel(level);
+    status_t status = lpTrack->setAuxEffectSendLevel(level);
+    if (status != NO_ERROR) {
+        ALOGE("AudioTrack::setAuxEffectSendLevel() for level %g failed with status %d",
+                level, status);
+    }
+    return (jint) status;
 }
 
 // ----------------------------------------------------------------------------
@@ -949,7 +958,7 @@
     {"native_get_min_buff_size",
                              "(III)I",   (void *)android_media_AudioTrack_get_min_buff_size},
     {"native_setAuxEffectSendLevel",
-                             "(F)V",     (void *)android_media_AudioTrack_setAuxEffectSendLevel},
+                             "(F)I",     (void *)android_media_AudioTrack_setAuxEffectSendLevel},
     {"native_attachAuxEffect",
                              "(I)I",     (void *)android_media_AudioTrack_attachAuxEffect},
 };
diff --git a/core/jni/android_view_GLRenderer.cpp b/core/jni/android_view_GLRenderer.cpp
index e45c1b9..180c625 100644
--- a/core/jni/android_view_GLRenderer.cpp
+++ b/core/jni/android_view_GLRenderer.cpp
@@ -26,6 +26,8 @@
 
 #include <utils/Timers.h>
 
+#include <private/hwui/DrawGlInfo.h>
+
 #include <Caches.h>
 #include <Extensions.h>
 #include <LayerRenderer.h>
@@ -155,6 +157,14 @@
     renderNode->updateProperties();
 }
 
+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
 
 // ----------------------------------------------------------------------------
@@ -187,6 +197,7 @@
     { "nDestroyLayer",         "(J)V",  (void*) android_view_GLRenderer_destroyLayer },
     { "nSetDisplayListData",  "(JJ)V", (void*) android_view_GLRenderer_setDisplayListData },
     { "nUpdateRenderNodeProperties", "(J)V", (void*) android_view_GLRenderer_updateRenderNodeProperties },
+    { "nInvokeFunctor",        "(JZ)V", (void*) android_view_GLRenderer_invokeFunctor },
 #endif
 
     { "setupShadersDiskCache", "(Ljava/lang/String;)V",
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index c5ab284..159ffb2 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -58,36 +58,11 @@
     jfieldID secure;
 } gPhysicalDisplayInfoClassInfo;
 
-
-class ScreenshotPixelRef : public SkPixelRef {
-public:
-    ScreenshotPixelRef(const SkImageInfo& info, ScreenshotClient* screenshot) :
-      SkPixelRef(info),
-      mScreenshot(screenshot) {
-        setImmutable();
-    }
-
-    virtual ~ScreenshotPixelRef() {
-        delete mScreenshot;
-    }
-
-protected:
-    // overrides from SkPixelRef
-    virtual void* onLockPixels(SkColorTable** ct) {
-        *ct = NULL;
-        return (void*)mScreenshot->getPixels();
-    }
-
-    virtual void onUnlockPixels() {
-    }
-
-    SK_DECLARE_UNFLATTENABLE_OBJECT()
-private:
-    ScreenshotClient* mScreenshot;
-
-    typedef SkPixelRef INHERITED;
-};
-
+// Implements SkMallocPixelRef::ReleaseProc, to delete the screenshot on unref.
+void DeleteScreenshot(void* addr, void* context) {
+    SkASSERT(addr == ((ScreenshotClient*) context)->getPixels());
+    delete ((ScreenshotClient*) context);
+}
 
 // ----------------------------------------------------------------------------
 
@@ -167,20 +142,19 @@
         }
     }
 
-    // takes ownership of ScreenshotClient
-    ScreenshotPixelRef* pixels = new ScreenshotPixelRef(screenshotInfo, screenshot);
     const ssize_t rowBytes =
             screenshot->getStride() * android::bytesPerPixel(screenshot->getFormat());
 
     SkBitmap* bitmap = new SkBitmap();
     bitmap->setConfig(screenshotInfo, (size_t)rowBytes);
     if (screenshotInfo.fWidth > 0 && screenshotInfo.fHeight > 0) {
+        // takes ownership of ScreenshotClient
+        SkMallocPixelRef* pixels = SkMallocPixelRef::NewWithProc(screenshotInfo,
+                (size_t) rowBytes, NULL, (void*) screenshot->getPixels(), &DeleteScreenshot,
+                (void*) screenshot);
+        pixels->setImmutable();
         bitmap->setPixelRef(pixels)->unref();
         bitmap->lockPixels();
-    } else {
-        // be safe with an empty bitmap.
-        delete pixels;
-        bitmap->setPixels(NULL);
     }
 
     return GraphicsJNI::createBitmap(env, bitmap,
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 28cee4b..98bec1b 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -139,6 +139,13 @@
     proxy->detachFunctor(functor);
 }
 
+static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jlong functorPtr, jboolean waitForCompletion) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
+    proxy->invokeFunctor(functor, waitForCompletion);
+}
+
 static void android_view_ThreadedRenderer_runWithGlContext(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jobject jrunnable) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -196,6 +203,7 @@
     { "nDestroyCanvas", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvas },
     { "nAttachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_attachFunctor },
     { "nDetachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_detachFunctor },
+    { "nInvokeFunctor", "(JJZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
     { "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext },
     { "nCreateDisplayListLayer", "(JII)J", (void*) android_view_ThreadedRenderer_createDisplayListLayer },
     { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
new file mode 100644
index 0000000..a61fa87
--- /dev/null
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -0,0 +1,608 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "android_runtime/AndroidRuntime.h"
+
+// sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
+#include <sys/mount.h>
+#include <linux/fs.h>
+
+#include <grp.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "cutils/fs.h"
+#include "cutils/multiuser.h"
+#include "cutils/sched_policy.h"
+#include "utils/String8.h"
+#include "JNIHelp.h"
+#include "ScopedLocalRef.h"
+#include "ScopedPrimitiveArray.h"
+#include "ScopedUtfChars.h"
+
+#if defined(HAVE_PRCTL)
+#include <sys/prctl.h>
+#endif
+
+#include <selinux/android.h>
+
+#if defined(__linux__)
+#include <sys/personality.h>
+#include <sys/utsname.h>
+#if defined(HAVE_ANDROID_OS)
+#include <sys/capability.h>
+#endif
+#endif
+
+namespace {
+
+using android::String8;
+
+static pid_t gSystemServerPid = 0;
+
+static const char kZygoteClassName[] = "com/android/internal/os/Zygote";
+static jclass gZygoteClass;
+static jmethodID gCallPostForkChildHooks;
+
+// Must match values in com.android.internal.os.Zygote.
+enum MountExternalKind {
+  MOUNT_EXTERNAL_NONE = 0,
+  MOUNT_EXTERNAL_SINGLEUSER = 1,
+  MOUNT_EXTERNAL_MULTIUSER = 2,
+  MOUNT_EXTERNAL_MULTIUSER_ALL = 3,
+};
+
+static void RuntimeAbort(JNIEnv* env) {
+  env->FatalError("RuntimeAbort");
+}
+
+// This signal handler is for zygote mode, since the zygote must reap its children
+static void SigChldHandler(int /*signal_number*/) {
+  pid_t pid;
+  int status;
+
+  while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+     // Log process-death status that we care about.  In general it is
+     // not safe to call LOG(...) from a signal handler because of
+     // possible reentrancy.  However, we know a priori that the
+     // current implementation of LOG() is safe to call from a SIGCHLD
+     // handler in the zygote process.  If the LOG() implementation
+     // changes its locking strategy or its use of syscalls within the
+     // lazy-init critical section, its use here may become unsafe.
+    if (WIFEXITED(status)) {
+      if (WEXITSTATUS(status)) {
+        ALOGI("Process %d exited cleanly (%d)", pid, WEXITSTATUS(status));
+      } else if (false) {
+        ALOGI("Process %d exited cleanly (%d)", pid, WEXITSTATUS(status));
+      }
+    } else if (WIFSIGNALED(status)) {
+      if (WTERMSIG(status) != SIGKILL) {
+        ALOGI("Process %d exited cleanly (%d)", pid, WTERMSIG(status));
+      } else if (false) {
+        ALOGI("Process %d exited cleanly (%d)", pid, WTERMSIG(status));
+      }
+#ifdef WCOREDUMP
+      if (WCOREDUMP(status)) {
+        ALOGI("Process %d dumped core.", pid);
+      }
+#endif /* ifdef WCOREDUMP */
+    }
+
+    // If the just-crashed process is the system_server, bring down zygote
+    // so that it is restarted by init and system server will be restarted
+    // from there.
+    if (pid == gSystemServerPid) {
+      ALOGE("Exit zygote because system server (%d) has terminated");
+      kill(getpid(), SIGKILL);
+    }
+  }
+
+  if (pid < 0) {
+    ALOGW("Zygote SIGCHLD error in waitpid: %d", errno);
+  }
+}
+
+// Configures the SIGCHLD handler for the zygote process. This is configured
+// very late, because earlier in the runtime we may fork() and exec()
+// other processes, and we want to waitpid() for those rather than
+// have them be harvested immediately.
+//
+// This ends up being called repeatedly before each fork(), but there's
+// no real harm in that.
+static void SetSigChldHandler() {
+  struct sigaction sa;
+  memset(&sa, 0, sizeof(sa));
+  sa.sa_handler = SigChldHandler;
+
+  int err = sigaction(SIGCHLD, &sa, NULL);
+  if (err < 0) {
+    ALOGW("Error setting SIGCHLD handler: %d", errno);
+  }
+}
+
+// Sets the SIGCHLD handler back to default behavior in zygote children.
+static void UnsetSigChldHandler() {
+  struct sigaction sa;
+  memset(&sa, 0, sizeof(sa));
+  sa.sa_handler = SIG_DFL;
+
+  int err = sigaction(SIGCHLD, &sa, NULL);
+  if (err < 0) {
+    ALOGW("Error unsetting SIGCHLD handler: %d", errno);
+  }
+}
+
+// Calls POSIX setgroups() using the int[] object as an argument.
+// A NULL argument is tolerated.
+static void SetGids(JNIEnv* env, jintArray javaGids) {
+  if (javaGids == NULL) {
+    return;
+  }
+
+  ScopedIntArrayRO gids(env, javaGids);
+  if (gids.get() == NULL) {
+      RuntimeAbort(env);
+  }
+  int rc = setgroups(gids.size(), reinterpret_cast<const gid_t*>(&gids[0]));
+  if (rc == -1) {
+    ALOGE("setgroups failed");
+    RuntimeAbort(env);
+  }
+}
+
+// Sets the resource limits via setrlimit(2) for the values in the
+// two-dimensional array of integers that's passed in. The second dimension
+// contains a tuple of length 3: (resource, rlim_cur, rlim_max). NULL is
+// treated as an empty array.
+static void SetRLimits(JNIEnv* env, jobjectArray javaRlimits) {
+  if (javaRlimits == NULL) {
+    return;
+  }
+
+  rlimit rlim;
+  memset(&rlim, 0, sizeof(rlim));
+
+  for (int i = 0; i < env->GetArrayLength(javaRlimits); ++i) {
+    ScopedLocalRef<jobject> javaRlimitObject(env, env->GetObjectArrayElement(javaRlimits, i));
+    ScopedIntArrayRO javaRlimit(env, reinterpret_cast<jintArray>(javaRlimitObject.get()));
+    if (javaRlimit.size() != 3) {
+      ALOGE("rlimits array must have a second dimension of size 3");
+      RuntimeAbort(env);
+    }
+
+    rlim.rlim_cur = javaRlimit[1];
+    rlim.rlim_max = javaRlimit[2];
+
+    int rc = setrlimit(javaRlimit[0], &rlim);
+    if (rc == -1) {
+      ALOGE("setrlimit(%d, {%d, %d}) failed", javaRlimit[0], rlim.rlim_cur, rlim.rlim_max);
+      RuntimeAbort(env);
+    }
+  }
+}
+
+#if defined(HAVE_ANDROID_OS)
+
+// The debug malloc library needs to know whether it's the zygote or a child.
+extern "C" int gMallocLeakZygoteChild;
+
+static void EnableKeepCapabilities(JNIEnv* env) {
+  int rc = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+  if (rc == -1) {
+    ALOGE("prctl(PR_SET_KEEPCAPS) failed");
+    RuntimeAbort(env);
+  }
+}
+
+static void DropCapabilitiesBoundingSet(JNIEnv* env) {
+  for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
+    int rc = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
+    if (rc == -1) {
+      if (errno == EINVAL) {
+        ALOGE("prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify "
+              "your kernel is compiled with file capabilities support");
+      } else {
+        ALOGE("prctl(PR_CAPBSET_DROP) failed");
+        RuntimeAbort(env);
+      }
+    }
+  }
+}
+
+static void SetCapabilities(JNIEnv* env, int64_t permitted, int64_t effective) {
+  __user_cap_header_struct capheader;
+  memset(&capheader, 0, sizeof(capheader));
+  capheader.version = _LINUX_CAPABILITY_VERSION_3;
+  capheader.pid = 0;
+
+  __user_cap_data_struct capdata[2];
+  memset(&capdata, 0, sizeof(capdata));
+  capdata[0].effective = effective;
+  capdata[1].effective = effective >> 32;
+  capdata[0].permitted = permitted;
+  capdata[1].permitted = permitted >> 32;
+
+  if (capset(&capheader, &capdata[0]) == -1) {
+    ALOGE("capset(%lld, %lld) failed", permitted, effective);
+    RuntimeAbort(env);
+  }
+}
+
+static void SetSchedulerPolicy(JNIEnv* env) {
+  errno = -set_sched_policy(0, SP_DEFAULT);
+  if (errno != 0) {
+    ALOGE("set_sched_policy(0, SP_DEFAULT) failed");
+    RuntimeAbort(env);
+  }
+}
+
+#else
+
+static int gMallocLeakZygoteChild = 0;
+
+static void EnableKeepCapabilities(JNIEnv*) {}
+static void DropCapabilitiesBoundingSet(JNIEnv*) {}
+static void SetCapabilities(JNIEnv*, int64_t, int64_t) {}
+static void SetSchedulerPolicy(JNIEnv*) {}
+
+#endif
+
+// Create a private mount namespace and bind mount appropriate emulated
+// storage for the given user.
+static bool MountEmulatedStorage(uid_t uid, jint mount_mode) {
+  if (mount_mode == MOUNT_EXTERNAL_NONE) {
+    return true;
+  }
+
+  // See storage config details at http://source.android.com/tech/storage/
+  userid_t user_id = multiuser_get_user_id(uid);
+
+  // Create a second private mount namespace for our process
+  if (unshare(CLONE_NEWNS) == -1) {
+      ALOGW("Failed to unshare(): %d", errno);
+      return false;
+  }
+
+  // Create bind mounts to expose external storage
+  if (mount_mode == MOUNT_EXTERNAL_MULTIUSER || mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
+    // These paths must already be created by init.rc
+    const char* source = getenv("EMULATED_STORAGE_SOURCE");
+    const char* target = getenv("EMULATED_STORAGE_TARGET");
+    const char* legacy = getenv("EXTERNAL_STORAGE");
+    if (source == NULL || target == NULL || legacy == NULL) {
+      ALOGW("Storage environment undefined; unable to provide external storage");
+      return false;
+    }
+
+    // Prepare source paths
+
+    // /mnt/shell/emulated/0
+    const String8 source_user(String8::format("%s/%d", source, user_id));
+    // /storage/emulated/0
+    const String8 target_user(String8::format("%s/%d", target, user_id));
+
+    if (fs_prepare_dir(source_user.string(), 0000, 0, 0) == -1
+        || fs_prepare_dir(target_user.string(), 0000, 0, 0) == -1) {
+      return false;
+    }
+
+    if (mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
+      // Mount entire external storage tree for all users
+      if (TEMP_FAILURE_RETRY(mount(source, target, NULL, MS_BIND, NULL)) == -1) {
+        ALOGW("Failed to mount %s to %s :%d", source, target, errno);
+        return false;
+      }
+    } else {
+      // Only mount user-specific external storage
+      if (TEMP_FAILURE_RETRY(
+              mount(source_user.string(), target_user.string(), NULL, MS_BIND, NULL)) == -1) {
+        ALOGW("Failed to mount %s to %s: %d", source_user.string(), target_user.string(), errno);
+        return false;
+      }
+    }
+
+    if (fs_prepare_dir(legacy, 0000, 0, 0) == -1) {
+        return false;
+    }
+
+    // Finally, mount user-specific path into place for legacy users
+    if (TEMP_FAILURE_RETRY(
+            mount(target_user.string(), legacy, NULL, MS_BIND | MS_REC, NULL)) == -1) {
+      ALOGW("Failed to mount %s to %s: %d", target_user.string(), legacy, errno);
+      return false;
+    }
+  } else {
+    ALOGW("Mount mode %d unsupported", mount_mode);
+    return false;
+  }
+
+  return true;
+}
+
+#if defined(__linux__)
+static bool NeedsNoRandomizeWorkaround() {
+#if !defined(__arm__)
+    return false;
+#else
+    int major;
+    int minor;
+    struct utsname uts;
+    if (uname(&uts) == -1) {
+        return false;
+    }
+
+    if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
+        return false;
+    }
+
+    // Kernels before 3.4.* need the workaround.
+    return (major < 3) || ((major == 3) && (minor < 4));
+#endif
+}
+#endif
+
+// Utility to close down the Zygote socket file descriptors while
+// the child is still running as root with Zygote's privileges.  Each
+// descriptor (if any) is closed via dup2(), replacing it with a valid
+// (open) descriptor to /dev/null.
+
+static void DetachDescriptors(JNIEnv* env, jintArray fdsToClose) {
+  if (!fdsToClose) {
+    return;
+  }
+  jsize count = env->GetArrayLength(fdsToClose);
+  jint *ar = env->GetIntArrayElements(fdsToClose, 0);
+  if (!ar) {
+      ALOGE("Bad fd array");
+      RuntimeAbort(env);
+  }
+  jsize i;
+  int devnull;
+  for (i = 0; i < count; i++) {
+    devnull = open("/dev/null", O_RDWR);
+    if (devnull < 0) {
+      ALOGE("Failed to open /dev/null");
+      RuntimeAbort(env);
+      continue;
+    }
+    ALOGV("Switching descriptor %d to /dev/null: %d", ar[i], errno);
+    if (dup2(devnull, ar[i]) < 0) {
+      ALOGE("Failed dup2() on descriptor %d", ar[i]);
+      RuntimeAbort(env);
+    }
+    close(devnull);
+  }
+}
+
+void SetThreadName(const char* thread_name) {
+  bool hasAt = false;
+  bool hasDot = false;
+  const char* s = thread_name;
+  while (*s) {
+    if (*s == '.') {
+      hasDot = true;
+    } else if (*s == '@') {
+      hasAt = true;
+    }
+    s++;
+  }
+  const int len = s - thread_name;
+  if (len < 15 || hasAt || !hasDot) {
+    s = thread_name;
+  } else {
+    s = thread_name + len - 15;
+  }
+  // pthread_setname_np fails rather than truncating long strings.
+  char buf[16];       // MAX_TASK_COMM_LEN=16 is hard-coded into bionic
+  strlcpy(buf, s, sizeof(buf)-1);
+  errno = pthread_setname_np(pthread_self(), buf);
+  if (errno != 0) {
+    ALOGW("Unable to set the name of current thread to '%s'", buf);
+  }
+}
+
+// Utility routine to fork zygote and specialize the child process.
+static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
+                                     jint debug_flags, jobjectArray javaRlimits,
+                                     jlong permittedCapabilities, jlong effectiveCapabilities,
+                                     jint mount_external,
+                                     jstring java_se_info, jstring java_se_name,
+                                     bool is_system_server, jintArray fdsToClose) {
+  SetSigChldHandler();
+
+  pid_t pid = fork();
+
+  if (pid == 0) {
+    // The child process.
+    gMallocLeakZygoteChild = 1;
+
+    // Clean up any descriptors which must be closed immediately
+    DetachDescriptors(env, fdsToClose);
+
+    // Keep capabilities across UID change, unless we're staying root.
+    if (uid != 0) {
+      EnableKeepCapabilities(env);
+    }
+
+    DropCapabilitiesBoundingSet(env);
+
+    if (!MountEmulatedStorage(uid, mount_external)) {
+      ALOGW("Failed to mount emulated storage: %d", errno);
+      if (errno == ENOTCONN || errno == EROFS) {
+        // When device is actively encrypting, we get ENOTCONN here
+        // since FUSE was mounted before the framework restarted.
+        // When encrypted device is booting, we get EROFS since
+        // FUSE hasn't been created yet by init.
+        // In either case, continue without external storage.
+      } else {
+        ALOGE("Cannot continue without emulated storage");
+        RuntimeAbort(env);
+      }
+    }
+
+    SetGids(env, javaGids);
+
+    SetRLimits(env, javaRlimits);
+
+    int rc = setresgid(gid, gid, gid);
+    if (rc == -1) {
+      ALOGE("setresgid(%d) failed", gid);
+      RuntimeAbort(env);
+    }
+
+    rc = setresuid(uid, uid, uid);
+    if (rc == -1) {
+      ALOGE("setresuid(%d) failed", uid);
+      RuntimeAbort(env);
+    }
+
+#if defined(__linux__)
+    if (NeedsNoRandomizeWorkaround()) {
+        // Work around ARM kernel ASLR lossage (http://b/5817320).
+        int old_personality = personality(0xffffffff);
+        int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
+        if (new_personality == -1) {
+            ALOGW("personality(%d) failed", new_personality);
+        }
+    }
+#endif
+
+    SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
+
+    SetSchedulerPolicy(env);
+
+#if defined(HAVE_ANDROID_OS)
+    {  // NOLINT(whitespace/braces)
+      const char* se_info_c_str = NULL;
+      ScopedUtfChars* se_info = NULL;
+      if (java_se_info != NULL) {
+          se_info = new ScopedUtfChars(env, java_se_info);
+          se_info_c_str = se_info->c_str();
+          if (se_info_c_str == NULL) {
+            ALOGE("se_info_c_str == NULL");
+            RuntimeAbort(env);
+          }
+      }
+      const char* se_name_c_str = NULL;
+      ScopedUtfChars* se_name = NULL;
+      if (java_se_name != NULL) {
+          se_name = new ScopedUtfChars(env, java_se_name);
+          se_name_c_str = se_name->c_str();
+          if (se_name_c_str == NULL) {
+            ALOGE("se_name_c_str == NULL");
+            RuntimeAbort(env);
+          }
+      }
+      rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
+      if (rc == -1) {
+        ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
+              is_system_server, se_info_c_str, se_name_c_str);
+        RuntimeAbort(env);
+      }
+
+      // Make it easier to debug audit logs by setting the main thread's name to the
+      // nice name rather than "app_process".
+      if (se_info_c_str == NULL && is_system_server) {
+        se_name_c_str = "system_server";
+      }
+      if (se_info_c_str != NULL) {
+        SetThreadName(se_name_c_str);
+      }
+
+      delete se_info;
+      delete se_name;
+    }
+#else
+    UNUSED(is_system_server);
+    UNUSED(java_se_info);
+    UNUSED(java_se_name);
+#endif
+
+    UnsetSigChldHandler();
+
+    env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags);
+    if (env->ExceptionCheck()) {
+      ALOGE("Error calling post fork hooks.");
+      RuntimeAbort(env);
+    }
+  } else if (pid > 0) {
+    // the parent process
+  }
+  return pid;
+}
+}  // anonymous namespace
+
+namespace android {
+
+static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
+        JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
+        jint debug_flags, jobjectArray rlimits,
+        jint mount_external, jstring se_info, jstring se_name,
+        jintArray fdsToClose) {
+    return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
+            rlimits, 0, 0, mount_external, se_info, se_name, false, fdsToClose);
+}
+
+static jint com_android_internal_os_Zygote_nativeForkSystemServer(
+        JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
+        jint debug_flags, jobjectArray rlimits, jlong permittedCapabilities,
+        jlong effectiveCapabilities) {
+  pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
+                                      debug_flags, rlimits,
+                                      permittedCapabilities, effectiveCapabilities,
+                                      MOUNT_EXTERNAL_NONE, NULL, NULL, true, NULL);
+  if (pid > 0) {
+      // The zygote process checks whether the child process has died or not.
+      ALOGI("System server process %d has been created", pid);
+      gSystemServerPid = pid;
+      // There is a slight window that the system server process has crashed
+      // but it went unnoticed because we haven't published its pid yet. So
+      // we recheck here just to make sure that all is well.
+      int status;
+      if (waitpid(pid, &status, WNOHANG) == pid) {
+          ALOGE("System server process %d has died. Restarting Zygote!", pid);
+          RuntimeAbort(env);
+      }
+  }
+  return pid;
+}
+
+static JNINativeMethod gMethods[] = {
+    { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[I)I",
+      (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
+    { "nativeForkSystemServer", "(II[II[[IJJ)I",
+      (void *) com_android_internal_os_Zygote_nativeForkSystemServer }
+};
+
+int register_com_android_internal_os_Zygote(JNIEnv* env) {
+  gZygoteClass = (jclass) env->NewGlobalRef(env->FindClass(kZygoteClassName));
+  if (gZygoteClass == NULL) {
+    RuntimeAbort(env);
+  }
+  gCallPostForkChildHooks = env->GetStaticMethodID(gZygoteClass, "callPostForkChildHooks", "(I)V");
+
+  return AndroidRuntime::registerNativeMethods(env, "com/android/internal/os/Zygote",
+      gMethods, NELEM(gMethods));
+}
+}  // namespace android
+
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2168bd1..2a4d872 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2547,6 +2547,21 @@
         android:label="@string/permlab_control_keyguard"
         android:description="@string/permdesc_control_keyguard" />
 
+    <!-- Allows an application to listen to trust changes.  Only allowed for system processes.
+        @hide -->
+    <permission android:name="android.permission.TRUST_LISTENER"
+                android:protectionLevel="signature"
+                android:label="@string/permlab_trust_listener"
+                android:description="@string/permdesc_trust_listener" />
+
+    <!-- Must be required by an {@link
+         android.service.trust.TrustAgentService},
+         to ensure that only the system can bind to it. -->
+    <permission android:name="android.permission.BIND_TRUST_AGENT_SERVICE"
+                android:protectionLevel="signature"
+                android:label="@string/permlab_bind_trust_agent_service"
+                android:description="@string/permdesc_bind_trust_agent_service" />
+
     <!-- Must be required by an {@link
          android.service.notification.NotificationListenerService},
          to ensure that only the system can bind to it. -->
diff --git a/core/res/res/drawable-hdpi/ab_bottom_solid_qntm_alpha.9.png b/core/res/res/drawable-hdpi/ab_bottom_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..406bf58
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ab_bottom_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ab_bottom_transparent_qntm_alpha.9.png b/core/res/res/drawable-hdpi/ab_bottom_transparent_qntm_alpha.9.png
new file mode 100644
index 0000000..409d3cd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ab_bottom_transparent_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ab_share_pack_qntm_alpha.9.png b/core/res/res/drawable-hdpi/ab_share_pack_qntm_alpha.9.png
new file mode 100644
index 0000000..b07da0c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ab_share_pack_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ab_solid_qntm_alpha.9.png b/core/res/res/drawable-hdpi/ab_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..9d7b25f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ab_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ab_solid_shadow_qntm.9.png b/core/res/res/drawable-hdpi/ab_solid_shadow_qntm.9.png
deleted file mode 100644
index 717ec1a..0000000
--- a/core/res/res/drawable-hdpi/ab_solid_shadow_qntm.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ab_solid_shadow_qntm_alpha.9.png b/core/res/res/drawable-hdpi/ab_solid_shadow_qntm_alpha.9.png
new file mode 100644
index 0000000..e49ad54
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ab_solid_shadow_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ab_stacked_solid_qntm_alpha.9.png b/core/res/res/drawable-hdpi/ab_stacked_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..1222711
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ab_stacked_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ab_stacked_transparent_qntm_alpha.9.png b/core/res/res/drawable-hdpi/ab_stacked_transparent_qntm_alpha.9.png
new file mode 100644
index 0000000..d0fcc25
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ab_stacked_transparent_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_qntm_alpha.9.png b/core/res/res/drawable-hdpi/btn_cab_done_qntm_alpha.9.png
new file mode 100644
index 0000000..992a8ff
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_cab_done_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_rating_star_off_qntm_alpha.png
new file mode 100644
index 0000000..51a895d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_rating_star_on_qntm_alpha.png
new file mode 100644
index 0000000..2f59488
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_disabled_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_media_route_disabled_qntm_alpha.png
new file mode 100644
index 0000000..e0a2ba1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_disabled_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_off_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_media_route_off_qntm_alpha.png
new file mode 100644
index 0000000..d37e8ee
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_0_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_media_route_on_0_qntm_alpha.png
new file mode 100644
index 0000000..0c604d9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_0_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_1_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_media_route_on_1_qntm_alpha.png
new file mode 100644
index 0000000..2c3f4ff
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_1_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_2_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_media_route_on_2_qntm_alpha.png
new file mode 100644
index 0000000..991c50e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_2_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_media_route_on_qntm_alpha.png
new file mode 100644
index 0000000..05fb919
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_bottom_solid_qntm_alpha.9.png b/core/res/res/drawable-mdpi/ab_bottom_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..219d311
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ab_bottom_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_bottom_transparent_qntm_alpha.9.png b/core/res/res/drawable-mdpi/ab_bottom_transparent_qntm_alpha.9.png
new file mode 100644
index 0000000..bfdc933
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ab_bottom_transparent_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_share_pack_qntm_alpha.9.png b/core/res/res/drawable-mdpi/ab_share_pack_qntm_alpha.9.png
new file mode 100644
index 0000000..f31730d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ab_share_pack_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_solid_qntm_alpha.9.png b/core/res/res/drawable-mdpi/ab_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..bd818b5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ab_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_solid_shadow_qntm.9.png b/core/res/res/drawable-mdpi/ab_solid_shadow_qntm.9.png
deleted file mode 100644
index c00c545..0000000
--- a/core/res/res/drawable-mdpi/ab_solid_shadow_qntm.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_solid_shadow_qntm_alpha.9.png b/core/res/res/drawable-mdpi/ab_solid_shadow_qntm_alpha.9.png
new file mode 100644
index 0000000..ebdea00
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ab_solid_shadow_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_stacked_solid_qntm_alpha.9.png b/core/res/res/drawable-mdpi/ab_stacked_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..41c7ce6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ab_stacked_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_stacked_transparent_qntm_alpha.9.png b/core/res/res/drawable-mdpi/ab_stacked_transparent_qntm_alpha.9.png
new file mode 100644
index 0000000..961a73e5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ab_stacked_transparent_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_qntm_alpha.9.png b/core/res/res/drawable-mdpi/btn_cab_done_qntm_alpha.9.png
new file mode 100644
index 0000000..5903856
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_cab_done_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_rating_star_off_qntm_alpha.png
new file mode 100644
index 0000000..d38aed2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_rating_star_on_qntm_alpha.png
new file mode 100644
index 0000000..87dade3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_disabled_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_media_route_disabled_qntm_alpha.png
new file mode 100644
index 0000000..ec43047
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_disabled_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_off_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_media_route_off_qntm_alpha.png
new file mode 100644
index 0000000..a652117
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_0_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_media_route_on_0_qntm_alpha.png
new file mode 100644
index 0000000..35d1c56
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_0_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_1_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_media_route_on_1_qntm_alpha.png
new file mode 100644
index 0000000..264188b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_1_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_2_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_media_route_on_2_qntm_alpha.png
new file mode 100644
index 0000000..06ae665
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_2_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_media_route_on_qntm_alpha.png
new file mode 100644
index 0000000..a69e301
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_bottom_solid_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/ab_bottom_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..312f76c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ab_bottom_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_bottom_transparent_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/ab_bottom_transparent_qntm_alpha.9.png
new file mode 100644
index 0000000..49e0a49
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ab_bottom_transparent_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_share_pack_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/ab_share_pack_qntm_alpha.9.png
new file mode 100644
index 0000000..8337ffe
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ab_share_pack_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_solid_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/ab_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..fb0d0b6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ab_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_solid_shadow_qntm.9.png b/core/res/res/drawable-xhdpi/ab_solid_shadow_qntm.9.png
deleted file mode 100644
index 1443b7f..0000000
--- a/core/res/res/drawable-xhdpi/ab_solid_shadow_qntm.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_solid_shadow_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/ab_solid_shadow_qntm_alpha.9.png
new file mode 100644
index 0000000..f51af63
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ab_solid_shadow_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_stacked_solid_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/ab_stacked_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..6d87890
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ab_stacked_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_stacked_transparent_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/ab_stacked_transparent_qntm_alpha.9.png
new file mode 100644
index 0000000..58f3e0f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ab_stacked_transparent_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_qntm_alpha.9.png
new file mode 100644
index 0000000..d0d0b1e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_cab_done_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_qntm_alpha.png
new file mode 100644
index 0000000..33ec44c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_qntm_alpha.png
new file mode 100644
index 0000000..0166d70
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_disabled_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_media_route_disabled_qntm_alpha.png
new file mode 100644
index 0000000..a020d64
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_disabled_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_off_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_media_route_off_qntm_alpha.png
new file mode 100644
index 0000000..e75ffb8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_0_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_media_route_on_0_qntm_alpha.png
new file mode 100644
index 0000000..1b9fc12
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_0_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_1_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_media_route_on_1_qntm_alpha.png
new file mode 100644
index 0000000..f63d47e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_1_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_2_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_media_route_on_2_qntm_alpha.png
new file mode 100644
index 0000000..fe005d9
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_2_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_media_route_on_qntm_alpha.png
new file mode 100644
index 0000000..ea86408
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_bottom_solid_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/ab_bottom_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..65b8d4a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_bottom_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_bottom_transparent_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/ab_bottom_transparent_qntm_alpha.9.png
new file mode 100644
index 0000000..a397baa
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_bottom_transparent_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_share_pack_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/ab_share_pack_qntm_alpha.9.png
new file mode 100644
index 0000000..469f736
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_share_pack_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_solid_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/ab_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..b56fa4a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_solid_shadow_qntm.9.png b/core/res/res/drawable-xxhdpi/ab_solid_shadow_qntm.9.png
deleted file mode 100644
index e89c9fe..0000000
--- a/core/res/res/drawable-xxhdpi/ab_solid_shadow_qntm.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_solid_shadow_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/ab_solid_shadow_qntm_alpha.9.png
new file mode 100644
index 0000000..e8a94dc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_solid_shadow_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_stacked_solid_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/ab_stacked_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..71b9737
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_stacked_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_stacked_transparent_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/ab_stacked_transparent_qntm_alpha.9.png
new file mode 100644
index 0000000..e2cc715
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_stacked_transparent_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_transparent_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/ab_transparent_qntm_alpha.9.png
index f220168..605d1de 100644
--- a/core/res/res/drawable-xxhdpi/ab_transparent_qntm_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/ab_transparent_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_cab_done_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/btn_cab_done_qntm_alpha.9.png
new file mode 100644
index 0000000..e1c55ad
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_cab_done_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_qntm_alpha.png
new file mode 100644
index 0000000..4b49faf
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_qntm_alpha.png
new file mode 100644
index 0000000..561d9ef
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_disabled_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_qntm_alpha.png
new file mode 100644
index 0000000..6fad4a64
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_off_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_media_route_off_qntm_alpha.png
new file mode 100644
index 0000000..44d98d5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_0_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_qntm_alpha.png
new file mode 100644
index 0000000..c807b50
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_1_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_qntm_alpha.png
new file mode 100644
index 0000000..d54f44a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_2_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_qntm_alpha.png
new file mode 100644
index 0000000..17c1d99
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_qntm_alpha.png
new file mode 100644
index 0000000..906401e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable/ab_bottom_solid_quantum.xml b/core/res/res/drawable/ab_bottom_solid_quantum.xml
new file mode 100644
index 0000000..848737e
--- /dev/null
+++ b/core/res/res/drawable/ab_bottom_solid_quantum.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/ab_bottom_solid_qntm_alpha"
+    android:tint="?attr/colorBackground"
+    android:tintMode="multiply" />
diff --git a/core/res/res/drawable/ab_bottom_transparent_quantum.xml b/core/res/res/drawable/ab_bottom_transparent_quantum.xml
new file mode 100644
index 0000000..29df6b9
--- /dev/null
+++ b/core/res/res/drawable/ab_bottom_transparent_quantum.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/ab_bottom_transparent_qntm_alpha"
+    android:tint="?attr/colorBackground"
+    android:tintMode="multiply" />
diff --git a/core/res/res/drawable/ab_share_pack_quantum.xml b/core/res/res/drawable/ab_share_pack_quantum.xml
new file mode 100644
index 0000000..7d33ff4d
--- /dev/null
+++ b/core/res/res/drawable/ab_share_pack_quantum.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/ab_share_pack_qntm_alpha"
+    android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ab_solid_quantum.xml b/core/res/res/drawable/ab_solid_quantum.xml
new file mode 100644
index 0000000..e56bb40
--- /dev/null
+++ b/core/res/res/drawable/ab_solid_quantum.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/ab_solid_qntm_alpha"
+    android:tint="?attr/colorBackground"
+    android:tintMode="multiply" />
diff --git a/core/res/res/drawable/ab_solid_shadow_quantum.xml b/core/res/res/drawable/ab_solid_shadow_quantum.xml
new file mode 100644
index 0000000..88e142a
--- /dev/null
+++ b/core/res/res/drawable/ab_solid_shadow_quantum.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/ab_solid_shadow_qntm_alpha"
+    android:tint="@color/black" />
diff --git a/core/res/res/drawable/ab_stacked_solid_quantum.xml b/core/res/res/drawable/ab_stacked_solid_quantum.xml
new file mode 100644
index 0000000..df775af
--- /dev/null
+++ b/core/res/res/drawable/ab_stacked_solid_quantum.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/ab_stacked_solid_qntm_alpha"
+    android:tint="?attr/colorBackground"
+    android:tintMode="multiply" />
diff --git a/core/res/res/drawable/ab_stacked_transparent_quantum.xml b/core/res/res/drawable/ab_stacked_transparent_quantum.xml
new file mode 100644
index 0000000..bdae6b9
--- /dev/null
+++ b/core/res/res/drawable/ab_stacked_transparent_quantum.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/ab_stacked_transparent_qntm_alpha"
+    android:tint="?attr/colorBackground"
+    android:tintMode="multiply" />
diff --git a/core/res/res/drawable/btn_cab_done_quantum.xml b/core/res/res/drawable/btn_cab_done_quantum.xml
new file mode 100644
index 0000000..c03ab0a
--- /dev/null
+++ b/core/res/res/drawable/btn_cab_done_quantum.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true">
+    <item android:state_pressed="true">
+        <color android:color="?attr/colorButtonPressed" />
+    </item>
+    <item android:state_focused="true" android:state_enabled="true">
+        <nine-patch android:src="@drawable/btn_cab_done_qntm_alpha"
+            android:tint="?attr/colorButtonPressed" />
+    </item>
+    <item android:state_enabled="true">
+        <nine-patch android:src="@drawable/btn_cab_done_qntm_alpha"
+            android:tint="?attr/colorButtonNormal" />
+    </item>
+</selector>
diff --git a/core/res/res/drawable/ic_media_route_connecting_quantum.xml b/core/res/res/drawable/ic_media_route_connecting_quantum.xml
new file mode 100644
index 0000000..0029dd4
--- /dev/null
+++ b/core/res/res/drawable/ic_media_route_connecting_quantum.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
+    android:oneshot="false">
+    <item android:duration="500">
+        <bitmap android:src="@drawable/ic_media_route_on_0_qntm_alpha"
+            android:tint="?attr/colorControlNormal" />
+    </item>
+    <item android:duration="500">
+        <bitmap android:src="@drawable/ic_media_route_on_1_qntm_alpha"
+            android:tint="?attr/colorControlNormal" />
+    </item>
+    <item android:duration="500">
+        <bitmap android:src="@drawable/ic_media_route_on_2_qntm_alpha"
+            android:tint="?attr/colorControlNormal" />
+    </item>
+    <item android:duration="500">
+        <bitmap android:src="@drawable/ic_media_route_on_1_qntm_alpha"
+            android:tint="?attr/colorControlNormal" />
+    </item>
+</animation-list>
diff --git a/core/res/res/drawable/ic_media_route_quantum.xml b/core/res/res/drawable/ic_media_route_quantum.xml
new file mode 100644
index 0000000..16b63d4
--- /dev/null
+++ b/core/res/res/drawable/ic_media_route_quantum.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_checked="true" android:state_enabled="true"
+        android:drawable="@android:drawable/ic_media_route_connecting_quantum" />
+    <item android:state_activated="true" android:state_enabled="true">
+        <bitmap android:src="@android:drawable/ic_media_route_on_qntm_alpha"
+            android:tint="?attr/colorControlNormal" />
+    </item>
+    <item android:state_enabled="true">
+        <bitmap android:src="@android:drawable/ic_media_route_off_qntm_alpha"
+            android:tint="?attr/colorControlNormal" />
+    </item>
+    <item>
+        <bitmap android:src="@android:drawable/ic_media_route_disabled_qntm_alpha"
+            android:tint="?attr/colorControlNormal" />
+    </item>
+</selector>
diff --git a/core/res/res/drawable/ratingbar_full_empty_quantum.xml b/core/res/res/drawable/ratingbar_full_empty_quantum.xml
new file mode 100644
index 0000000..e5e4315
--- /dev/null
+++ b/core/res/res/drawable/ratingbar_full_empty_quantum.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <bitmap android:src="@drawable/btn_rating_star_off_qntm_alpha"
+            android:tint="?attr/colorControlActivated" />
+    </item>
+    <item>
+        <bitmap android:src="@drawable/btn_rating_star_off_qntm_alpha"
+            android:tint="?attr/colorControlNormal" />
+    </item>
+</selector>
diff --git a/core/res/res/drawable/ratingbar_full_filled_quantum.xml b/core/res/res/drawable/ratingbar_full_filled_quantum.xml
new file mode 100644
index 0000000..ad3aa5d
--- /dev/null
+++ b/core/res/res/drawable/ratingbar_full_filled_quantum.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <bitmap android:src="@drawable/btn_rating_star_on_qntm_alpha"
+            android:tint="?attr/colorControlActivated" />
+    </item>
+    <item>
+        <bitmap android:src="@drawable/btn_rating_star_on_qntm_alpha"
+            android:tint="?attr/colorControlNormal" />
+    </item>
+</selector>
diff --git a/core/res/res/drawable/ratingbar_full_quantum.xml b/core/res/res/drawable/ratingbar_full_quantum.xml
new file mode 100644
index 0000000..143e7c2
--- /dev/null
+++ b/core/res/res/drawable/ratingbar_full_quantum.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@id/background"
+        android:drawable="@drawable/ratingbar_full_empty_quantum" />
+    <item android:id="@id/secondaryProgress"
+        android:drawable="@drawable/ratingbar_full_empty_quantum" />
+    <item android:id="@id/progress" 
+        android:drawable="@drawable/ratingbar_full_filled_quantum" />
+</layer-list>
diff --git a/core/res/res/layout/alert_dialog_progress_quantum.xml b/core/res/res/layout/alert_dialog_progress_quantum.xml
new file mode 100644
index 0000000..b9d0814
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_progress_quantum.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="match_parent">
+    <ProgressBar android:id="@+id/progress"
+        style="?android:attr/progressBarStyleHorizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dip"
+        android:layout_marginBottom="1dip"
+        android:layout_marginStart="16dip"
+        android:layout_marginEnd="16dip"
+        android:layout_centerHorizontal="true" />
+    <TextView
+        android:id="@+id/progress_percent"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingBottom="16dip"
+        android:layout_marginStart="16dip"
+        android:layout_marginEnd="16dip"
+        android:layout_alignParentStart="true"
+        android:layout_below="@id/progress" />
+    <TextView
+        android:id="@+id/progress_number"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingBottom="16dip"
+        android:layout_marginStart="16dip"
+        android:layout_marginEnd="16dip"
+        android:layout_alignParentEnd="true"
+        android:layout_below="@id/progress" />
+</RelativeLayout>
diff --git a/core/res/res/layout/alert_dialog_quantum.xml b/core/res/res/layout/alert_dialog_quantum.xml
new file mode 100644
index 0000000..4cc76ca
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_quantum.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/parentPanel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginStart="8dip"
+    android:layout_marginEnd="8dip"
+    android:orientation="vertical">
+
+    <LinearLayout android:id="@+id/topPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+        <View android:id="@+id/titleDividerTop"
+            android:layout_width="match_parent"
+            android:layout_height="2dip"
+            android:visibility="gone"
+            android:background="@android:color/holo_blue_light" />
+        <LinearLayout android:id="@+id/title_template"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:gravity="center_vertical|start"
+            android:minHeight="@dimen/alert_dialog_title_height"
+            android:layout_marginStart="16dip"
+            android:layout_marginEnd="16dip">
+            <ImageView android:id="@+id/icon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingEnd="8dip"
+                android:src="@null" />
+            <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
+                style="?android:attr/windowTitleStyle"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAlignment="viewStart" />
+        </LinearLayout>
+        <View android:id="@+id/titleDivider"
+            android:layout_width="match_parent"
+            android:layout_height="2dip"
+            android:visibility="gone"
+            android:background="@android:color/holo_blue_light" />
+        <!-- If the client uses a customTitle, it will be added here. -->
+    </LinearLayout>
+
+    <LinearLayout android:id="@+id/contentPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:minHeight="64dp">
+        <ScrollView android:id="@+id/scrollView"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:clipToPadding="false">
+            <TextView android:id="@+id/message"
+                style="?android:attr/textAppearanceMedium"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:paddingStart="16dip"
+                android:paddingEnd="16dip"
+                android:paddingTop="8dip"
+                android:paddingBottom="8dip"/>
+        </ScrollView>
+    </LinearLayout>
+
+    <FrameLayout android:id="@+id/customPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:minHeight="64dp">
+        <FrameLayout android:id="@+android:id/custom"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+    </FrameLayout>
+
+    <LinearLayout android:id="@+id/buttonPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="@dimen/alert_dialog_button_bar_height"
+        android:orientation="vertical"
+        android:dividerPadding="0dip">
+        <LinearLayout
+            style="?android:attr/buttonBarStyle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:layoutDirection="locale"
+            android:measureWithLargestChild="true">
+            <Button android:id="@+id/button2"
+                android:layout_width="wrap_content"
+                android:layout_gravity="start"
+                android:layout_weight="1"
+                android:maxLines="2"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                android:layout_height="wrap_content" />
+            <Button android:id="@+id/button3"
+                android:layout_width="wrap_content"
+                android:layout_gravity="center_horizontal"
+                android:layout_weight="1"
+                android:maxLines="2"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                android:layout_height="wrap_content" />
+            <Button android:id="@+id/button1"
+                android:layout_width="wrap_content"
+                android:layout_gravity="end"
+                android:layout_weight="1"
+                android:maxLines="2"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:layout_height="wrap_content" />
+        </LinearLayout>
+     </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/progress_dialog_quantum.xml b/core/res/res/layout/progress_dialog_quantum.xml
new file mode 100644
index 0000000..84d06b5
--- /dev/null
+++ b/core/res/res/layout/progress_dialog_quantum.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <LinearLayout android:id="@+id/body"
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:baselineAligned="false"
+        android:padding="16dip">
+
+        <ProgressBar android:id="@android:id/progress"
+            style="?android:attr/progressBarStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:max="10000"
+            android:layout_marginEnd="16dip" />
+
+        <TextView android:id="@+id/message"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical" />
+    </LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/select_dialog_item_quantum.xml b/core/res/res/layout/select_dialog_item_quantum.xml
new file mode 100644
index 0000000..59b432e
--- /dev/null
+++ b/core/res/res/layout/select_dialog_item_quantum.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!--
+    This layout file is used by the AlertDialog when displaying a list of items.
+    This layout file is inflated and used as the TextView to display individual
+    items.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:textAppearance="?android:attr/textAppearanceListItemSmall"
+    android:textColor="?android:attr/textColorAlertDialogListItem"
+    android:gravity="center_vertical"
+    android:paddingStart="16dip"
+    android:paddingEnd="16dip"
+    android:ellipsize="marquee" />
diff --git a/core/res/res/layout/select_dialog_multichoice_quantum.xml b/core/res/res/layout/select_dialog_multichoice_quantum.xml
new file mode 100644
index 0000000..8b4c59d
--- /dev/null
+++ b/core/res/res/layout/select_dialog_multichoice_quantum.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:textAppearance="?android:attr/textAppearanceMedium"
+    android:textColor="?android:attr/textColorAlertDialogListItem"
+    android:gravity="center_vertical"
+    android:paddingStart="16dip"
+    android:paddingEnd="16dip"
+    android:checkMark="?android:attr/listChoiceIndicatorMultiple"
+    android:ellipsize="marquee" />
diff --git a/core/res/res/layout/select_dialog_quantum.xml b/core/res/res/layout/select_dialog_quantum.xml
new file mode 100644
index 0000000..ee04039
--- /dev/null
+++ b/core/res/res/layout/select_dialog_quantum.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!--
+    This layout file is used by the AlertDialog when displaying a list of items.
+    This layout file is inflated and used as the ListView to display the items.
+    Assign an ID so its state will be saved/restored.
+-->
+<view class="com.android.internal.app.AlertController$RecycleListView"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+android:id/select_dialog_listview"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:cacheColorHint="@null"
+    android:divider="?android:attr/listDividerAlertDialog"
+    android:scrollbars="vertical"
+    android:overScrollMode="ifContentScrolls"
+    android:textAlignment="viewStart" />
diff --git a/core/res/res/layout/select_dialog_singlechoice_quantum.xml b/core/res/res/layout/select_dialog_singlechoice_quantum.xml
new file mode 100644
index 0000000..27a6648
--- /dev/null
+++ b/core/res/res/layout/select_dialog_singlechoice_quantum.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:textAppearance="?android:attr/textAppearanceMedium"
+    android:textColor="?android:attr/textColorAlertDialogListItem"
+    android:gravity="center_vertical"
+    android:paddingStart="16dip"
+    android:paddingEnd="16dip"
+    android:checkMark="?android:attr/listChoiceIndicatorSingle"
+    android:ellipsize="marquee" />
diff --git a/core/res/res/layout/tab_indicator_quantum.xml b/core/res/res/layout/tab_indicator_quantum.xml
new file mode 100644
index 0000000..fcb2d5f
--- /dev/null
+++ b/core/res/res/layout/tab_indicator_quantum.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="?android:attr/actionBarSize"
+    android:orientation="horizontal"
+    style="@android:style/Widget.Quantum.Tab">
+
+    <ImageView
+        android:id="@android:id/icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:visibility="gone" />
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        style="@android:style/Widget.Quantum.TabText" />
+
+</LinearLayout>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 0d8c1f1..0e5a0e7 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -988,7 +988,7 @@
     <string name="search_go" msgid="8298016669822141719">"ፍለጋ"</string>
     <string name="searchview_description_search" msgid="6749826639098512120">"ፍለጋ"</string>
     <string name="searchview_description_query" msgid="5911778593125355124">"ጥያቄ ፍለጋ"</string>
-    <string name="searchview_description_clear" msgid="1330281990951833033">"ጥያቄ አጥራ"</string>
+    <string name="searchview_description_clear" msgid="1330281990951833033">"ጥያቄ አጽዳ"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"ጥያቄ አስረክብ"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"የድምፅ ፍለጋ"</string>
     <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"በመንካት አስስ ይንቃ?"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index a59378f..80a4ed27 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -145,7 +145,7 @@
     <string name="silent_mode" msgid="7167703389802618663">"Lautlos-Modus"</string>
     <string name="turn_on_radio" msgid="3912793092339962371">"Funk einschalten"</string>
     <string name="turn_off_radio" msgid="8198784949987062346">"Funk ausschalten"</string>
-    <string name="screen_lock" msgid="799094655496098153">"Display-Sperre"</string>
+    <string name="screen_lock" msgid="799094655496098153">"Displaysperre"</string>
     <string name="power_off" msgid="4266614107412865048">"Ausschalten"</string>
     <string name="silent_mode_silent" msgid="319298163018473078">"Klingelton aus"</string>
     <string name="silent_mode_vibrate" msgid="7072043388581551395">"Klingeltonmodus \"Vibration\""</string>
@@ -160,7 +160,7 @@
     <string name="no_recent_tasks" msgid="8794906658732193473">"Keine kürzlich geöffneten Apps"</string>
     <string name="global_actions" product="tablet" msgid="408477140088053665">"Tablet-Optionen"</string>
     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonoptionen"</string>
-    <string name="global_action_lock" msgid="2844945191792119712">"Display-Sperre"</string>
+    <string name="global_action_lock" msgid="2844945191792119712">"Displaysperre"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Ausschalten"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Fehlerbericht"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Fehlerbericht abrufen"</string>
@@ -633,7 +633,7 @@
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Ermöglicht der App, die Bluetooth-Konfiguration des Telefons einzusehen und Verbindungen mit gekoppelten Geräten herzustellen und zu akzeptieren."</string>
     <string name="permlab_nfc" msgid="4423351274757876953">"Nahfeldkommunikation steuern"</string>
     <string name="permdesc_nfc" msgid="7120611819401789907">"Ermöglicht der App die Kommunikation mit Tags für die Nahfeldkommunikation, Karten und Readern"</string>
-    <string name="permlab_disableKeyguard" msgid="3598496301486439258">"Display-Sperre deaktivieren"</string>
+    <string name="permlab_disableKeyguard" msgid="3598496301486439258">"Displaysperre deaktivieren"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Ermöglicht der App, die Tastensperre sowie den damit verbundenen Passwortschutz zu deaktivieren. Das Telefon deaktiviert die Tastensperre beispielsweise, wenn ein Anruf eingeht, und aktiviert sie wieder, nachdem das Gespräch beendet wurde."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"Synchronisierungseinstellungen lesen"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Ermöglicht der App, die Synchronisierungseinstellungen eines Kontos zu lesen. Beispielsweise kann damit festgestellt werden, ob Kontakte mit einem Konto synchronisiert werden."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 2c8b5d2..899c4f9 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -233,7 +233,7 @@
     <string name="permgrouplab_display" msgid="4279909676036402636">"Používateľské rozhranie iných aplikácií"</string>
     <string name="permgroupdesc_display" msgid="6051002031933013714">"Vplyv na používateľské rozhranie ďalších aplikácií."</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Úložisko"</string>
-    <string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Prístup do ukl. priestoru USB."</string>
+    <string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Prístup do úložiska USB."</string>
     <string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Prístup na kartu SD."</string>
     <string name="permgrouplab_accessibilityFeatures" msgid="7919025602283593907">"Funkcie zjednodušenia ovládania"</string>
     <string name="permgroupdesc_accessibilityFeatures" msgid="4205196881678144335">"Funkcie, ktoré môže vyžadovať nápomocná technológia."</string>
@@ -347,7 +347,7 @@
     <string name="permdesc_backup" msgid="6912230525140589891">"Umožňuje aplikácii ovládať mechanizmus na zálohovanie a obnovu údajov systému. Bežné aplikácie toto nastavenie nepoužívajú."</string>
     <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"potvrdenie operácie úplnej zálohy alebo úplného obnovenia"</string>
     <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Umožňuje aplikácii spustiť používateľské rozhranie potvrdenia úplnej zálohy. Toto nastavenie by nemala používať žiadna aplikácia."</string>
-    <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"zobrazenie neoprávnených okien"</string>
+    <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"zobraziť neoprávnené okná"</string>
     <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Umožňuje aplikácii vytvárať okná, ktoré majú byť použité interným systémom používateľského rozhrania. Bežné aplikácie toto nastavenie nepoužívajú."</string>
     <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"vykresliť cez ďalšie aplikácie"</string>
     <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Umožňuje aplikáciu vykresľovanie nad inými aplikáciami alebo súčasťami používateľského rozhrania. Táto funkcia môže zasahovať do vášho používania rozhrania inej aplikácie alebo meniť zobrazovaný obsah v iných aplikáciách."</string>
@@ -474,9 +474,9 @@
     <string name="permdesc_accessLocationExtraCommands" msgid="5945166642335800763">"Umožňuje aplikácii pristupovať k ďalším príkazom poskytovateľa informácií o polohe. Aplikácii to môže umožniť zasahovať do činnosti systému GPS alebo iných zdrojov informácií o polohe."</string>
     <string name="permlab_installLocationProvider" msgid="6578101199825193873">"Oprávnenie na inštaláciu poskytovateľa polohy"</string>
     <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"Vytváranie simulovaných zdrojov polohy na testovanie alebo inštalácia nového poskytovateľa informácií o polohe. Aplikácii to umožní nahradiť polohu a stav, ktoré vracajú iné zdroje informácií o polohe, ako sú napríklad systém GPS alebo poskytovatelia informácií o polohe."</string>
-    <string name="permlab_accessFineLocation" msgid="1191898061965273372">"presná poloha (pomocou GPS a siete)"</string>
+    <string name="permlab_accessFineLocation" msgid="1191898061965273372">"zistiť presnú polohu (pomocou GPS a siete)"</string>
     <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Umožňuje aplikácii získať vašu presnú polohu pomocou systému GPS (Global Positioning System) alebo zdrojov určenia polohy siete, napríklad mobilných veží a sietí Wi-Fi. Tieto služby určovania polohy musia byť na vašom zariadení zapnuté a dostupné, inak ich aplikácia nebude môcť využívať. Aplikácie môžu tieto služby využívať na určenie vašej polohy. Tieto služby môžu zvýšiť spotrebu batérie."</string>
-    <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"približná poloha (pomocou siete)"</string>
+    <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"zistiť približnú polohu (pomocou siete)"</string>
     <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Umožňuje aplikácii získať vašu približnú polohu. Táto poloha je odvodená zo služieb určovania polohy pomocou zdrojov určenia polohy siete, napríklad mobilných veží a sietí Wi-Fi. Tieto služby určovania polohy musia byť na vašom zariadení zapnuté a dostupné, inak ich aplikácia nebude môcť využívať. Aplikácie môžu tieto služby využívať na určenie vašej približnej polohy."</string>
     <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"prístup k službe SurfaceFlinger"</string>
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Umožňuje aplikácii používať funkcie nízkej úrovne aplikácie SurfaceFlinger."</string>
@@ -498,13 +498,13 @@
     <string name="permdesc_captureSecureVideoOutput" msgid="2779793064709350289">"Umožňuje aplikácii zachytiť a presmerovať zabezpečený výstup videa."</string>
     <string name="permlab_mediaContentControl" msgid="8749790560720562511">"ovládanie reprodukcie médií a prístup k metadátam"</string>
     <string name="permdesc_mediaContentControl" msgid="1637478200272062">"Umožňuje aplikácii ovládať reprodukciu médií a pristupovať k informáciám o médiách (názov, autor...)."</string>
-    <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"zmeny vašich nastavení zvuku"</string>
+    <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"meniť nastavenia zvuku"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Umožňuje aplikácii upraviť globálne nastavenia zvuku, ako je hlasitosť, alebo určiť, z ktorého reproduktora bude zvuk vychádzať."</string>
-    <string name="permlab_recordAudio" msgid="3876049771427466323">"záznam zvuku"</string>
+    <string name="permlab_recordAudio" msgid="3876049771427466323">"nahrávať zvuk"</string>
     <string name="permdesc_recordAudio" msgid="4906839301087980680">"Umožňuje aplikácii zaznamenávať zvuk pomocou mikrofónu. Toto povolenie umožňuje aplikácii zaznamenávať zvuk kedykoľvek bez vášho potvrdenia."</string>
     <string name="permlab_sim_communication" msgid="1180265879464893029">"komunikácia s kartou SIM"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"Umožňuje aplikácii odosielať príkazy na kartu SIM. Toto je veľmi nebezpečné povolenie."</string>
-    <string name="permlab_camera" msgid="3616391919559751192">"snímanie fotografií a natáčanie videí"</string>
+    <string name="permlab_camera" msgid="3616391919559751192">"fotiť a nakrúcať videá"</string>
     <string name="permdesc_camera" msgid="8497216524735535009">"Umožňuje aplikácii fotografovať a nahrávať videá pomocou fotoaparátu. Toto povolenie umožňuje aplikácii používať fotoaparát kedykoľvek a bez vášho potvrdenia."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"Zakázať indikátor LED prenosu pri používaní fotoaparátu"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Umožňuje v predinštalovanej systémovej aplikácii zakázať indikátor LED používania fotoaparátu."</string>
@@ -534,7 +534,7 @@
     <string name="permdesc_asec_rename" msgid="1794757588472127675">"Umožňuje aplikácii premenovať interné úložisko."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ovládať vibrovanie"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Umožňuje aplikácii ovládať vibrácie."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ovládanie kontrolky"</string>
+    <string name="permlab_flashlight" msgid="2155920810121984215">"ovládať kontrolku"</string>
     <string name="permdesc_flashlight" msgid="6522284794568368310">"Umožňuje aplikácii ovládať svetlo."</string>
     <string name="permlab_manageUsb" msgid="1113453430645402723">"spravovať predvoľby a povolenia zariadení USB"</string>
     <string name="permdesc_manageUsb" msgid="7776155430218239833">"Umožňuje aplikácii spravovať predvoľby a povolenia zariadení USB."</string>
@@ -575,7 +575,7 @@
     <string name="permlab_factoryTest" msgid="3715225492696416187">"spustenie v režime továrenského testu"</string>
     <string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Umožňuje aplikácii spustenie v režime nízkoúrovňového testu výrobcu a povolí úplný prístup k hardvéru tabletu. K dispozícii iba vtedy, keď je tablet spustený v režime testovania výrobcu."</string>
     <string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Umožňuje aplikácii spustenie v režime nízkoúrovňového testu výrobcu a povolí úplný prístup k hardvéru telefónu. K dispozícii iba vtedy, keď je telefón spustený v režime testovania výrobcu."</string>
-    <string name="permlab_setWallpaper" msgid="6627192333373465143">"nastavenie tapety"</string>
+    <string name="permlab_setWallpaper" msgid="6627192333373465143">"nastaviť tapetu"</string>
     <string name="permdesc_setWallpaper" msgid="7373447920977624745">"Umožňuje aplikácii nastaviť tapetu systému."</string>
     <string name="permlab_setWallpaperHints" msgid="3278608165977736538">"upraviť veľkosť tapety"</string>
     <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Umožňuje aplikácii nastaviť tipy pre veľkosť tapety systému."</string>
@@ -610,7 +610,7 @@
     <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Umožňuje aplikácii zmeniť stav sieťového pripojenia zdieľaného pomocou tetheringu."</string>
     <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"zmeniť nastavenie použitia údajov na pozadí"</string>
     <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Umožňuje aplikácii zmeniť nastavenie používania údajov na pozadí."</string>
-    <string name="permlab_accessWifiState" msgid="5202012949247040011">"zobraziť pripojenia siete Wi-Fi"</string>
+    <string name="permlab_accessWifiState" msgid="5202012949247040011">"zobraziť pripojenia Wi-Fi"</string>
     <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Umožňuje aplikácii zobraziť informácie o sieťach Wi-Fi. Napríklad o tom, či je sieť Wi-Fi povolená alebo názvy pripojených zariadení Wi-Fi."</string>
     <string name="permlab_changeWifiState" msgid="6550641188749128035">"pripojiť a odpojiť od siete Wi-Fi"</string>
     <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Umožňuje aplikácii pripojiť sa na prístupové body siete Wi-Fi, odpojiť sa od nich a meniť konfiguráciu zariadení pre siete Wi-Fi."</string>
@@ -631,19 +631,19 @@
     <string name="permlab_bluetooth" msgid="6127769336339276828">"párovať so zariadeniami Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Umožňuje aplikácii zobraziť informácie o konfigurácii Bluetooth na tablete. Taktiež jej umožňuje nadväzovať a akceptovať spojenia so spárovanými zariadeniami."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Umožňuje aplikácii zobraziť informácie o konfigurácii Bluetooth na telefóne. Taktiež jej umožňuje nadväzovať a akceptovať spojenia so spárovanými zariadeniami."</string>
-    <string name="permlab_nfc" msgid="4423351274757876953">"ovládať technológiu Near Field Communication"</string>
-    <string name="permdesc_nfc" msgid="7120611819401789907">"Umožňuje aplikácii komunikovať so značkami, kartami a čítačkami s podporou technológie Near Field Communication (NFC)."</string>
+    <string name="permlab_nfc" msgid="4423351274757876953">"ovládať technológiu NFC"</string>
+    <string name="permdesc_nfc" msgid="7120611819401789907">"Umožňuje aplikácii komunikovať so značkami, kartami a čítačkami s podporou technológie NFC."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"deaktivácia zámky obrazovky"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Umožňuje aplikácii zakázať uzamknutie klávesnice a akékoľvek súvisiace zabezpečenie heslom. Príkladom je zakázanie uzamknutia klávesnice pri prichádzajúcom telefonickom hovore a jeho opätovné povolenie po skončení hovoru."</string>
-    <string name="permlab_readSyncSettings" msgid="6201810008230503052">"čítanie nastavení synchronizácie"</string>
+    <string name="permlab_readSyncSettings" msgid="6201810008230503052">"čítať nastavenia synchronizácie"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Umožňuje aplikácii čítať nastavenia synchronizácie v účte. Môže napríklad určiť, či je s účtom synchronizovaná aplikácia Ľudia."</string>
-    <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"prepínať nastavenie synchronizácie medzi hodnotou zapnuté a vypnuté"</string>
+    <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"zapnúť alebo vypnúť synchronizáciu"</string>
     <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Umožňuje aplikácii upraviť nastavenia synchronizácie v účte. Pomocou tohto povolenia je možné napríklad povoliť synchronizáciu aplikácie Ľudia s účtom."</string>
     <string name="permlab_readSyncStats" msgid="7396577451360202448">"čítanie štatistických údajov o synchronizácii"</string>
     <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Umožňuje aplikácii čítať štatistické informácie o synchronizácii v účte vrátane histórie uskutočnených synchronizácií a informácií o množstve synchronizovaných údajov."</string>
-    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"čítanie zdrojov prihlásených na odber"</string>
+    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"čítať odoberané informačné kanály"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Umožňuje aplikácii získať podrobnosti o aktuálne synchronizovaných informačných kanáloch."</string>
-    <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"zápis odoberaných zdrojov"</string>
+    <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"zapisovať odoberané informačné kanály"</string>
     <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Umožňuje aplikácii upraviť vaše aktuálne synchronizované informačné kanály. Škodlivé aplikácie môžu synchronizované informačné kanály zmeniť."</string>
     <string name="permlab_readDictionary" msgid="4107101525746035718">"čítať výrazy pridané do slovníka"</string>
     <string name="permdesc_readDictionary" msgid="659614600338904243">"Umožňuje aplikácii čítať všetky slová, názvy a frázy, ktoré mohol používateľ uložiť do svojho slovníka."</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index df7cde7..4d43831 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1677,6 +1677,7 @@
              that is, when in portrait. Can be either an absolute dimension
              or a fraction of the screen size in that dimension. -->
         <attr name="windowFixedHeightMajor" format="dimension|fraction" />
+        <attr name="windowOutsetBottom" format="dimension" />
     </declare-styleable>
 
     <!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -5925,6 +5926,16 @@
         <attr name="settingsActivity" />
     </declare-styleable>
 
+    <!-- Use <code>trust_agent</code> as the root tag of the XML resource that
+         describes an {@link android.service.trust.TrustAgentService}, which is
+         referenced from its {@link android.service.trust.TrustAgentService#TRUST_AGENT_META_DATA}
+         meta-data entry.  Described here are the attributes that can be included in that tag. -->
+    <declare-styleable name="TrustAgent">
+        <!-- Component name of an activity that allows the user to modify
+             the settings for this TrustAgent. -->
+        <attr name="settingsActivity" />
+    </declare-styleable>
+
     <!-- =============================== -->
     <!-- Accounts package class attributes -->
     <!-- =============================== -->
@@ -6033,16 +6044,16 @@
     <eat-comment />
     <declare-styleable name="GlowPadView">
         <!-- Reference to an array resource that be shown as targets around a circle. -->
-        <attr name="targetDrawables"/>
+        <attr name="targetDrawables" format="reference" />
 
         <!-- Reference to an array resource that be used as description for the targets around the circle. -->
-        <attr name="targetDescriptions"/>
+        <attr name="targetDescriptions" format="reference" />
 
         <!-- Reference to an array resource that be used to announce the directions with targets around the circle. -->
-        <attr name="directionDescriptions"/>
+        <attr name="directionDescriptions" format="reference" />
 
         <!-- Sets a drawable as the center. -->
-        <attr name="handleDrawable"/>
+        <attr name="handleDrawable" format="reference" />
 
         <!-- Drawable to use for wave ripple animation. -->
         <attr name="outerRingDrawable" format="reference"/>
@@ -6054,22 +6065,22 @@
         <attr name="innerRadius"/>
 
         <!-- Outer radius of glow area. Target icons will be drawn on this circle. -->
-        <attr name="outerRadius"/>
+        <attr name="outerRadius" format="dimension" />
 
         <!-- Radius of glow under finger. -->
         <attr name="glowRadius" format="dimension" />
 
         <!-- Tactile feedback duration for actions. Set to '0' for no vibration. -->
-        <attr name="vibrationDuration"/>
+        <attr name="vibrationDuration" format="integer" />
 
         <!-- How close we need to be before snapping to a target. -->
-        <attr name="snapMargin"/>
+        <attr name="snapMargin" format="dimension" />
 
         <!-- Number of waves/chevrons to show in animation. -->
-        <attr name="feedbackCount"/>
+        <attr name="feedbackCount" format="integer" />
 
         <!-- Used when the handle shouldn't wait to be hit before following the finger -->
-        <attr name="alwaysTrackFinger"/>
+        <attr name="alwaysTrackFinger" format="boolean" />
 
         <!-- Location along the circle of the first item, in degrees.-->
         <attr name="firstItemOffset" format="float" />
@@ -6086,45 +6097,6 @@
     </declare-styleable>
 
     <!-- =============================== -->
-    <!-- MultiWaveView class attributes -->
-    <!-- =============================== -->
-    <eat-comment />
-    <declare-styleable name="MultiWaveView">
-        <!-- Reference to an array resource that be shown as targets around a circle. -->
-        <attr name="targetDrawables" format="reference"/>
-
-        <!-- Reference to an array resource that be used as description for the targets around the circle. -->
-        <attr name="targetDescriptions" format="reference"/>
-
-        <!-- Reference to an array resource that be used to announce the directions with targets around the circle. -->
-        <attr name="directionDescriptions" format="reference"/>
-
-        <!-- Sets a drawable as the drag center. -->
-        <attr name="handleDrawable" format="reference" />
-
-        <!-- Drawables to use for chevron animations. May be null. -->
-        <attr name="chevronDrawables" format="reference"/>
-
-        <!-- Drawable to use for wave ripple animation. -->
-        <attr name="waveDrawable" format="reference" />
-
-        <!-- Outer radius of target circle. Icons will be drawn on this circle. -->
-        <attr name="outerRadius" format="dimension" />
-
-        <!-- Tactile feedback duration for actions. Set to '0' for no vibration. -->
-        <attr name="vibrationDuration" format="integer"/>
-
-        <!-- How close we need to be before snapping to a target. -->
-        <attr name="snapMargin" format="dimension" />
-
-        <!-- Number of waves/chevrons to show in animation. -->
-        <attr name="feedbackCount" format="integer" />
-
-        <!-- Used when the handle shouldn't wait to be hit before following the finger -->
-        <attr name="alwaysTrackFinger" format="boolean" />
-    </declare-styleable>
-
-    <!-- =============================== -->
     <!-- SizeAdaptiveLayout class attributes -->
     <!-- =============================== -->
     <eat-comment />
@@ -6167,6 +6139,8 @@
         <!-- Aspect to use when drawing LockPatternView. Choices are "square"(default), "lock_width"
              or "lock_height" -->
         <attr name="aspect" format="string" />
+        <!-- Color to use when drawing LockPatternView paths. -->
+        <attr name="pathColor" format="color|reference" />
     </declare-styleable>
 
     <!-- Use <code>recognition-service</code> as the root tag of the XML resource that
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4656f32..7ae5a03 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -950,7 +950,7 @@
     <!-- Max space (in MB) allocated to DownloadManager to store the downloaded
          files if they are to be stored in DownloadManager's data dir,
          which typically is /data/data/com.android.providers.downloads/files -->
-    <integer name="config_downloadDataDirSize">100</integer>
+    <integer name="config_downloadDataDirSize">200</integer>
 
     <!-- Max number of downloads allowed to proceed concurrently -->
     <integer name="config_MaxConcurrentDownloadsAllowed">5</integer>
@@ -1339,6 +1339,12 @@
          Example: com.google.android.myapp/.resolver.MyResolverActivity  -->
     <string name="config_customResolverActivity"></string>
 
+    <!-- Name of the activity that prompts the user to reject, accept, or whitelist
+         an adb host's public key, when an unwhitelisted host connects to the local adbd.
+         Can be customized for other product types -->
+    <string name="config_customAdbPublicKeyActivity"
+            >com.android.systemui/com.android.systemui.usb.UsbDebuggingActivity</string>
+
     <!-- Apps that are authorized to access shared accounts, overridden by product overlays -->
     <string name="config_appsAuthorizedForSharedAccounts">;com.android.settings;</string>
 
@@ -1421,4 +1427,5 @@
          1 - The device DOES have a permanent menu key; ignore autodetection.
          2 - The device DOES NOT have a permanent menu key; ignore autodetection. -->
     <integer name="config_overrideHasPermanentMenuKey">0</integer>
+
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d49980f..d4692f1 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2365,4 +2365,6 @@
   <public type="style" name="TextAppearance.Quantum.Caption" />
   <public type="style" name="TextAppearance.Quantum.Menu" />
   <public type="style" name="TextAppearance.Quantum.Button" />
+
+  <public type="style" name="Widget.Holo.Light.Button.Borderless" />
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0699e8b..3a4f059 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3651,6 +3651,16 @@
     <!-- Description of an application permission that lets it control keyguard. -->
     <string name="permdesc_control_keyguard">Allows an application to control keguard.</string>
 
+    <!-- Title of an application permission that lets it listen to trust state changes. -->
+    <string name="permlab_trust_listener">Listen to trust state changes.</string>
+    <!-- Description of an application permission that lets it listen to trust state changes. -->
+    <string name="permdesc_trust_listener">Allows an application to listen for changes in trust state.</string>
+
+    <!-- Title of an application permission that lets it bind to a trust agent service. -->
+    <string name="permlab_bind_trust_agent_service">Bind to a trust agent service</string>
+    <!-- Description of an application permission that lets it bind to a trust agent service. -->
+    <string name="permdesc_bind_trust_agent_service">Allows an application to bind to a trust agent service.</string>
+
     <!-- Title of an application permission that lets it interact with recovery. -->
     <string name="permlab_recovery">Interact with update and recovery system</string>
     <!-- Description of an application permission that lets it control keyguard. -->
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 512c9b8..629b2b7 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -32,731 +32,271 @@
  -->
 <resources>
     <!-- Widget Styles -->
-    <style name="Widget.DeviceDefault" parent="Widget.Holo" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Button" parent="Widget.Holo.Button" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Button.Small" parent="Widget.Holo.Button.Small" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Button.Inset" parent="Widget.Holo.Button.Inset" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Button.Toggle" parent="Widget.Holo.Button.Toggle" >
-
-    </style>
-    <style name="Widget.DeviceDefault.TextView" parent="Widget.Holo.TextView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.CheckedTextView" parent="Widget.Holo.CheckedTextView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.AutoCompleteTextView" parent="Widget.Holo.AutoCompleteTextView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.CompoundButton.CheckBox" parent="Widget.Holo.CompoundButton.CheckBox" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ListView.DropDown" parent="Widget.Holo.ListView.DropDown" >
-
-    </style>
-    <style name="Widget.DeviceDefault.EditText" parent="Widget.Holo.EditText" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ExpandableListView" parent="Widget.Holo.ExpandableListView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.GridView" parent="Widget.Holo.GridView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ImageButton" parent="Widget.Holo.ImageButton" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ListView" parent="Widget.Holo.ListView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.PopupWindow" parent="Widget.Holo.PopupWindow" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ProgressBar" parent="Widget.Holo.ProgressBar" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ProgressBar.Horizontal" parent="Widget.Holo.ProgressBar.Horizontal" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ProgressBar.Small" parent="Widget.Holo.ProgressBar.Small" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ProgressBar.Small.Title" parent="Widget.Holo.ProgressBar.Small.Title" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ProgressBar.Large" parent="Widget.Holo.ProgressBar.Large" >
-
-    </style>
-    <style name="Widget.DeviceDefault.SeekBar" parent="Widget.Holo.SeekBar" >
-
-    </style>
-    <style name="Widget.DeviceDefault.RatingBar" parent="Widget.Holo.RatingBar" >
-
-    </style>
-    <style name="Widget.DeviceDefault.RatingBar.Indicator" parent="Widget.Holo.RatingBar.Indicator" >
-
-    </style>
-    <style name="Widget.DeviceDefault.RatingBar.Small" parent="Widget.Holo.RatingBar.Small" >
-
-    </style>
-    <style name="Widget.DeviceDefault.CompoundButton.RadioButton" parent="Widget.Holo.CompoundButton.RadioButton" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ScrollView" parent="Widget.Holo.ScrollView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.HorizontalScrollView" parent="Widget.Holo.HorizontalScrollView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Spinner" parent="Widget.Holo.Spinner" >
-
-    </style>
-    <style name="Widget.DeviceDefault.CompoundButton.Star" parent="Widget.Holo.CompoundButton.Star" >
-
-    </style>
-    <style name="Widget.DeviceDefault.TabWidget" parent="Widget.Holo.TabWidget" >
-
-    </style>
-    <style name="Widget.DeviceDefault.WebTextView" parent="Widget.Holo.WebTextView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.WebView" parent="Widget.Holo.WebView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.DropDownItem" parent="Widget.Holo.DropDownItem" >
-
-    </style>
-    <style name="Widget.DeviceDefault.DropDownItem.Spinner" parent="Widget.Holo.DropDownItem.Spinner" >
-
-    </style>
-    <style name="Widget.DeviceDefault.TextView.SpinnerItem" parent="Widget.Holo.TextView.SpinnerItem" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ListPopupWindow" parent="Widget.Holo.ListPopupWindow" >
-
-    </style>
-    <style name="Widget.DeviceDefault.PopupMenu" parent="Widget.Holo.PopupMenu" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ActionButton" parent="Widget.Holo.ActionButton" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ActionButton.Overflow" parent="Widget.Holo.ActionButton.Overflow" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ActionButton.TextButton" parent="Widget.Holo.ActionButton.TextButton" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ActionMode" parent="Widget.Holo.ActionMode" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ActionButton.CloseMode" parent="Widget.Holo.ActionButton.CloseMode" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ActionBar" parent="Widget.Holo.ActionBar" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Button.Borderless" parent="Widget.Holo.Button.Borderless" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Tab" parent="Widget.Holo.Tab" >
-
-    </style>
-    <style name="Widget.DeviceDefault.CalendarView" parent="Widget.Holo.CalendarView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.DatePicker" parent="Widget.Holo.DatePicker" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ActionBar.TabView" parent="Widget.Holo.ActionBar.TabView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ActionBar.TabText" parent="Widget.Holo.ActionBar.TabText" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ActionBar.TabBar" parent="Widget.Holo.ActionBar.TabBar" >
-
-    </style>
-    <style name="Widget.DeviceDefault.ActionBar.Solid" parent="Widget.Holo.ActionBar.Solid" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Button.Borderless.Small" parent="Widget.Holo.Button.Borderless.Small" >
-
-    </style>
-    <style name="Widget.DeviceDefault.AbsListView" parent="Widget.Holo.AbsListView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Spinner.DropDown.ActionBar" parent="Widget.Holo.Spinner.DropDown.ActionBar" >
-
-    </style>
-    <style name="Widget.DeviceDefault.PopupWindow.ActionMode" parent="Widget.Holo.PopupWindow.ActionMode" >
-
-    </style>
-    <style name="Widget.DeviceDefault.CompoundButton.Switch" parent="Widget.Holo.CompoundButton.Switch">
-
-    </style>
-    <style name="Widget.DeviceDefault.ExpandableListView.White" parent="Widget.Holo.ExpandableListView.White">
-
-    </style>
-    <style name="Widget.DeviceDefault.FastScroll" parent="Widget.Holo.FastScroll">
-
-    </style>
-    <style name="Widget.DeviceDefault.FragmentBreadCrumbs" parent="Widget.Holo.FragmentBreadCrumbs">
-
-    </style>
-    <style name="Widget.DeviceDefault.Gallery" parent="Widget.Holo.Gallery">
-
-    </style>
-    <style name="Widget.DeviceDefault.GestureOverlayView" parent="Widget.Holo.GestureOverlayView">
-
-    </style>
-    <style name="Widget.DeviceDefault.ImageWell" parent="Widget.Holo.ImageWell">
-
-    </style>
-    <style name="Widget.DeviceDefault.KeyboardView" parent="Widget.Holo.KeyboardView">
-
-    </style>
-    <style name="Widget.DeviceDefault.ListView.White" parent="Widget.Holo.ListView.White">
-
-    </style>
-    <style name="Widget.DeviceDefault.NumberPicker" parent="Widget.Holo.NumberPicker">
-
-    </style>
-    <style name="Widget.DeviceDefault.PreferenceFrameLayout" parent="Widget.Holo.PreferenceFrameLayout">
-
-    </style>
-    <style name="Widget.DeviceDefault.ProgressBar.Inverse" parent="Widget.Holo.ProgressBar.Inverse">
-
-
-    </style>
-    <style name="Widget.DeviceDefault.ProgressBar.Large.Inverse" parent="Widget.Holo.ProgressBar.Large.Inverse">
-
-    </style>
-    <style name="Widget.DeviceDefault.ProgressBar.Small.Inverse" parent="Widget.Holo.ProgressBar.Small.Inverse">
-
-    </style>
-    <style name="Widget.DeviceDefault.QuickContactBadge.WindowLarge" parent="Widget.Holo.QuickContactBadge.WindowLarge">
-
-    </style>
-    <style name="Widget.DeviceDefault.QuickContactBadge.WindowMedium" parent="Widget.Holo.QuickContactBadge.WindowMedium">
-
-    </style>
-    <style name="Widget.DeviceDefault.QuickContactBadge.WindowSmall" parent="Widget.Holo.QuickContactBadge.WindowSmall">
-
-    </style>
-    <style name="Widget.DeviceDefault.QuickContactBadgeSmall.WindowLarge" parent="Widget.Holo.QuickContactBadgeSmall.WindowLarge">
-
-    </style>
-    <style name="Widget.DeviceDefault.QuickContactBadgeSmall.WindowMedium" parent="Widget.Holo.QuickContactBadgeSmall.WindowMedium">
-
-    </style>
-    <style name="Widget.DeviceDefault.QuickContactBadgeSmall.WindowSmall" parent="Widget.Holo.QuickContactBadgeSmall.WindowSmall">
-
-    </style>
-    <style name="Widget.DeviceDefault.Spinner.DropDown" parent="Widget.Holo.Spinner.DropDown">
-
-    </style>
-    <style name="Widget.DeviceDefault.StackView" parent="Widget.Holo.StackView">
-
-    </style>
-    <style name="Widget.DeviceDefault.TextSelectHandle" parent="Widget.Holo.TextSelectHandle">
-
-    </style>
-    <style name="Widget.DeviceDefault.TextSuggestionsPopupWindow" parent="Widget.Holo.TextSuggestionsPopupWindow">
-
-    </style>
-    <style name="Widget.DeviceDefault.TextView.ListSeparator" parent="Widget.Holo.TextView.ListSeparator">
-
-    </style>
-    <style name="Widget.DeviceDefault.TimePicker" parent="Widget.Holo.TimePicker">
-
-    </style>
-    <style name="Widget.DeviceDefault.Light" parent="Widget.Holo.Light" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.Button" parent="Widget.Holo.Light.Button" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.Button.Small" parent="Widget.Holo.Light.Button.Small" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.Button.Inset" parent="Widget.Holo.Light.Button.Inset" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.Button.Toggle" parent="Widget.Holo.Light.Button.Toggle" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.TextView" parent="Widget.Holo.Light.TextView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.CheckedTextView" parent="Widget.Holo.Light.CheckedTextView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.AutoCompleteTextView" parent="Widget.Holo.Light.AutoCompleteTextView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.CompoundButton.CheckBox" parent="Widget.Holo.Light.CompoundButton.CheckBox" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ListView.DropDown" parent="Widget.Holo.Light.ListView.DropDown" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.EditText" parent="Widget.Holo.Light.EditText" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ExpandableListView" parent="Widget.Holo.Light.ExpandableListView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.FastScroll" parent="Widget.Holo.Light.FastScroll">
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.FragmentBreadCrumbs" parent="Widget.Holo.Light.FragmentBreadCrumbs">
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.GridView" parent="Widget.Holo.Light.GridView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ImageButton" parent="Widget.Holo.Light.ImageButton" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ListView" parent="Widget.Holo.Light.ListView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.PopupWindow" parent="Widget.Holo.Light.PopupWindow" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ProgressBar" parent="Widget.Holo.Light.ProgressBar" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ProgressBar.Horizontal" parent="Widget.Holo.Light.ProgressBar.Horizontal" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ProgressBar.Small" parent="Widget.Holo.Light.ProgressBar.Small" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ProgressBar.Small.Title" parent="Widget.Holo.Light.ProgressBar.Small.Title" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ProgressBar.Large" parent="Widget.Holo.Light.ProgressBar.Large" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ProgressBar.Inverse" parent="Widget.Holo.Light.ProgressBar.Inverse" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ProgressBar.Small.Inverse" parent="Widget.Holo.Light.ProgressBar.Small.Inverse" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ProgressBar.Large.Inverse" parent="Widget.Holo.Light.ProgressBar.Large.Inverse" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.SeekBar" parent="Widget.Holo.Light.SeekBar" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.RatingBar" parent="Widget.Holo.Light.RatingBar" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.RatingBar.Indicator" parent="Widget.Holo.Light.RatingBar.Indicator" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.RatingBar.Small" parent="Widget.Holo.Light.RatingBar.Small" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.CompoundButton.RadioButton" parent="Widget.Holo.Light.CompoundButton.RadioButton" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ScrollView" parent="Widget.Holo.Light.ScrollView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.HorizontalScrollView" parent="Widget.Holo.Light.HorizontalScrollView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.Spinner" parent="Widget.Holo.Light.Spinner" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.CompoundButton.Star" parent="Widget.Holo.Light.CompoundButton.Star" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.TabWidget" parent="Widget.Holo.Light.TabWidget" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.WebTextView" parent="Widget.Holo.Light.WebTextView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.WebView" parent="Widget.Holo.Light.WebView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.DropDownItem" parent="Widget.Holo.Light.DropDownItem" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.DropDownItem.Spinner" parent="Widget.Holo.Light.DropDownItem.Spinner" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.TextView.SpinnerItem" parent="Widget.Holo.Light.TextView.SpinnerItem" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ListPopupWindow" parent="Widget.Holo.Light.ListPopupWindow" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.PopupMenu" parent="Widget.Holo.Light.PopupMenu" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.Tab" parent="Widget.Holo.Light.Tab" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.CalendarView" parent="Widget.Holo.Light.CalendarView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.Button.Borderless.Small" parent="Widget.Holo.Light.Button.Borderless.Small" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ActionButton" parent="Widget.Holo.Light.ActionButton" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ActionButton.Overflow" parent="Widget.Holo.Light.ActionButton.Overflow" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ActionMode" parent="Widget.Holo.Light.ActionMode" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ActionButton.CloseMode" parent="Widget.Holo.Light.ActionButton.CloseMode" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ActionBar" parent="Widget.Holo.Light.ActionBar" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ActionBar.TabView" parent="Widget.Holo.Light.ActionBar.TabView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ActionBar.TabText" parent="Widget.Holo.Light.ActionBar.TabText" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ActionBar.TabBar" parent="Widget.Holo.Light.ActionBar.TabBar" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ActionBar.Solid" parent="Widget.Holo.Light.ActionBar.Solid" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ActionBar.Solid.Inverse" parent="Widget.Holo.Light.ActionBar.Solid.Inverse" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ActionBar.TabBar.Inverse" parent="Widget.Holo.Light.ActionBar.TabBar.Inverse" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ActionBar.TabView.Inverse" parent="Widget.Holo.Light.ActionBar.TabView.Inverse" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ActionBar.TabText.Inverse" parent="Widget.Holo.Light.ActionBar.TabText.Inverse" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ActionMode.Inverse" parent="Widget.Holo.Light.ActionMode.Inverse" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.AbsListView" parent="Widget.Holo.Light.AbsListView" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.Spinner.DropDown.ActionBar" parent="Widget.Holo.Light.Spinner.DropDown.ActionBar" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.PopupWindow.ActionMode" parent="Widget.Holo.Light.PopupWindow.ActionMode" >
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.Button.Borderless" parent="Widget.Holo.Light.Button.Borderless">
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.DatePicker" parent="Widget.Holo.Light.DatePicker">
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ExpandableListView.White" parent="Widget.Holo.Light.ExpandableListView.White">
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.Gallery" parent="Widget.Holo.Light.Gallery">
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.GestureOverlayView" parent="Widget.Holo.Light.GestureOverlayView">
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ImageWell" parent="Widget.Holo.Light.ImageWell">
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ListView.White" parent="Widget.Holo.Light.ListView.White">
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.NumberPicker" parent="Widget.Holo.Light.NumberPicker">
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.Spinner.DropDown" parent="Widget.Holo.Light.Spinner.DropDown">
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.TextView.ListSeparator" parent="Widget.Holo.Light.TextView.ListSeparator">
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.TimePicker" parent="Widget.Holo.Light.TimePicker">
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.TextSuggestionsPopupWindow" parent="Widget.Holo.Light.TextSuggestionsPopupWindow">
-
-    </style>
+    <style name="Widget.DeviceDefault" parent="Widget.Quantum"/>
+    <style name="Widget.DeviceDefault.Button" parent="Widget.Quantum.Button"/>
+    <style name="Widget.DeviceDefault.Button.Small" parent="Widget.Quantum.Button.Small"/>
+    <style name="Widget.DeviceDefault.Button.Inset" parent="Widget.Quantum.Button.Inset"/>
+    <style name="Widget.DeviceDefault.Button.Toggle" parent="Widget.Quantum.Button.Toggle"/>
+    <style name="Widget.DeviceDefault.TextView" parent="Widget.Quantum.TextView"/>
+    <style name="Widget.DeviceDefault.CheckedTextView" parent="Widget.Quantum.CheckedTextView"/>
+    <style name="Widget.DeviceDefault.AutoCompleteTextView" parent="Widget.Quantum.AutoCompleteTextView"/>
+    <style name="Widget.DeviceDefault.CompoundButton.CheckBox" parent="Widget.Quantum.CompoundButton.CheckBox"/>
+    <style name="Widget.DeviceDefault.ListView.DropDown" parent="Widget.Quantum.ListView.DropDown"/>
+    <style name="Widget.DeviceDefault.EditText" parent="Widget.Quantum.EditText"/>
+    <style name="Widget.DeviceDefault.ExpandableListView" parent="Widget.Quantum.ExpandableListView"/>
+    <style name="Widget.DeviceDefault.GridView" parent="Widget.Quantum.GridView"/>
+    <style name="Widget.DeviceDefault.ImageButton" parent="Widget.Quantum.ImageButton"/>
+    <style name="Widget.DeviceDefault.ListView" parent="Widget.Quantum.ListView"/>
+    <style name="Widget.DeviceDefault.PopupWindow" parent="Widget.Quantum.PopupWindow"/>
+    <style name="Widget.DeviceDefault.ProgressBar" parent="Widget.Quantum.ProgressBar"/>
+    <style name="Widget.DeviceDefault.ProgressBar.Horizontal" parent="Widget.Quantum.ProgressBar.Horizontal"/>
+    <style name="Widget.DeviceDefault.ProgressBar.Small" parent="Widget.Quantum.ProgressBar.Small"/>
+    <style name="Widget.DeviceDefault.ProgressBar.Small.Title" parent="Widget.Quantum.ProgressBar.Small.Title"/>
+    <style name="Widget.DeviceDefault.ProgressBar.Large" parent="Widget.Quantum.ProgressBar.Large"/>
+    <style name="Widget.DeviceDefault.SeekBar" parent="Widget.Quantum.SeekBar"/>
+    <style name="Widget.DeviceDefault.RatingBar" parent="Widget.Quantum.RatingBar"/>
+    <style name="Widget.DeviceDefault.RatingBar.Indicator" parent="Widget.Quantum.RatingBar.Indicator"/>
+    <style name="Widget.DeviceDefault.RatingBar.Small" parent="Widget.Quantum.RatingBar.Small"/>
+    <style name="Widget.DeviceDefault.CompoundButton.RadioButton" parent="Widget.Quantum.CompoundButton.RadioButton"/>
+    <style name="Widget.DeviceDefault.ScrollView" parent="Widget.Quantum.ScrollView"/>
+    <style name="Widget.DeviceDefault.HorizontalScrollView" parent="Widget.Quantum.HorizontalScrollView"/>
+    <style name="Widget.DeviceDefault.Spinner" parent="Widget.Quantum.Spinner"/>
+    <style name="Widget.DeviceDefault.CompoundButton.Star" parent="Widget.Quantum.CompoundButton.Star"/>
+    <style name="Widget.DeviceDefault.TabWidget" parent="Widget.Quantum.TabWidget"/>
+    <style name="Widget.DeviceDefault.WebTextView" parent="Widget.Quantum.WebTextView"/>
+    <style name="Widget.DeviceDefault.WebView" parent="Widget.Quantum.WebView"/>
+    <style name="Widget.DeviceDefault.DropDownItem" parent="Widget.Quantum.DropDownItem"/>
+    <style name="Widget.DeviceDefault.DropDownItem.Spinner" parent="Widget.Quantum.DropDownItem.Spinner"/>
+    <style name="Widget.DeviceDefault.TextView.SpinnerItem" parent="Widget.Quantum.TextView.SpinnerItem"/>
+    <style name="Widget.DeviceDefault.ListPopupWindow" parent="Widget.Quantum.ListPopupWindow"/>
+    <style name="Widget.DeviceDefault.PopupMenu" parent="Widget.Quantum.PopupMenu"/>
+    <style name="Widget.DeviceDefault.ActionButton" parent="Widget.Quantum.ActionButton"/>
+    <style name="Widget.DeviceDefault.ActionButton.Overflow" parent="Widget.Quantum.ActionButton.Overflow"/>
+    <style name="Widget.DeviceDefault.ActionButton.TextButton" parent="Widget.Quantum.ActionButton.TextButton"/>
+    <style name="Widget.DeviceDefault.ActionMode" parent="Widget.Quantum.ActionMode"/>
+    <style name="Widget.DeviceDefault.ActionButton.CloseMode" parent="Widget.Quantum.ActionButton.CloseMode"/>
+    <style name="Widget.DeviceDefault.ActionBar" parent="Widget.Quantum.ActionBar"/>
+    <style name="Widget.DeviceDefault.Button.Borderless" parent="Widget.Quantum.Button.Borderless"/>
+    <style name="Widget.DeviceDefault.Tab" parent="Widget.Quantum.Tab"/>
+    <style name="Widget.DeviceDefault.CalendarView" parent="Widget.Quantum.CalendarView"/>
+    <style name="Widget.DeviceDefault.DatePicker" parent="Widget.Quantum.DatePicker"/>
+    <style name="Widget.DeviceDefault.ActionBar.TabView" parent="Widget.Quantum.ActionBar.TabView"/>
+    <style name="Widget.DeviceDefault.ActionBar.TabText" parent="Widget.Quantum.ActionBar.TabText"/>
+    <style name="Widget.DeviceDefault.ActionBar.TabBar" parent="Widget.Quantum.ActionBar.TabBar"/>
+    <style name="Widget.DeviceDefault.ActionBar.Solid" parent="Widget.Quantum.ActionBar.Solid"/>
+    <style name="Widget.DeviceDefault.Button.Borderless.Small" parent="Widget.Quantum.Button.Borderless.Small"/>
+    <style name="Widget.DeviceDefault.AbsListView" parent="Widget.Quantum.AbsListView"/>
+    <style name="Widget.DeviceDefault.Spinner.DropDown.ActionBar" parent="Widget.Quantum.Spinner.DropDown.ActionBar"/>
+    <style name="Widget.DeviceDefault.PopupWindow.ActionMode" parent="Widget.Quantum.PopupWindow.ActionMode"/>
+    <style name="Widget.DeviceDefault.CompoundButton.Switch" parent="Widget.Quantum.CompoundButton.Switch"/>
+    <style name="Widget.DeviceDefault.ExpandableListView.White" parent="Widget.Quantum.ExpandableListView.White"/>
+    <style name="Widget.DeviceDefault.FastScroll" parent="Widget.Quantum.FastScroll"/>
+    <style name="Widget.DeviceDefault.FragmentBreadCrumbs" parent="Widget.Quantum.FragmentBreadCrumbs"/>
+    <style name="Widget.DeviceDefault.Gallery" parent="Widget.Quantum.Gallery"/>
+    <style name="Widget.DeviceDefault.GestureOverlayView" parent="Widget.Quantum.GestureOverlayView"/>
+    <style name="Widget.DeviceDefault.ImageWell" parent="Widget.Quantum.ImageWell"/>
+    <style name="Widget.DeviceDefault.KeyboardView" parent="Widget.Quantum.KeyboardView"/>
+    <style name="Widget.DeviceDefault.ListView.White" parent="Widget.Quantum.ListView.White"/>
+    <style name="Widget.DeviceDefault.NumberPicker" parent="Widget.Quantum.NumberPicker"/>
+    <style name="Widget.DeviceDefault.PreferenceFrameLayout" parent="Widget.Quantum.PreferenceFrameLayout"/>
+    <style name="Widget.DeviceDefault.ProgressBar.Inverse" parent="Widget.Quantum.ProgressBar.Inverse"/>
+    <style name="Widget.DeviceDefault.ProgressBar.Large.Inverse" parent="Widget.Quantum.ProgressBar.Large.Inverse"/>
+    <style name="Widget.DeviceDefault.ProgressBar.Small.Inverse" parent="Widget.Quantum.ProgressBar.Small.Inverse"/>
+    <style name="Widget.DeviceDefault.QuickContactBadge.WindowLarge" parent="Widget.Quantum.QuickContactBadge.WindowLarge"/>
+    <style name="Widget.DeviceDefault.QuickContactBadge.WindowMedium" parent="Widget.Quantum.QuickContactBadge.WindowMedium"/>
+    <style name="Widget.DeviceDefault.QuickContactBadge.WindowSmall" parent="Widget.Quantum.QuickContactBadge.WindowSmall"/>
+    <style name="Widget.DeviceDefault.QuickContactBadgeSmall.WindowLarge" parent="Widget.Quantum.QuickContactBadgeSmall.WindowLarge"/>
+    <style name="Widget.DeviceDefault.QuickContactBadgeSmall.WindowMedium" parent="Widget.Quantum.QuickContactBadgeSmall.WindowMedium"/>
+    <style name="Widget.DeviceDefault.QuickContactBadgeSmall.WindowSmall" parent="Widget.Quantum.QuickContactBadgeSmall.WindowSmall"/>
+    <style name="Widget.DeviceDefault.Spinner.DropDown" parent="Widget.Quantum.Spinner.DropDown"/>
+    <style name="Widget.DeviceDefault.StackView" parent="Widget.Quantum.StackView"/>
+    <style name="Widget.DeviceDefault.TextSelectHandle" parent="Widget.Quantum.TextSelectHandle"/>
+    <style name="Widget.DeviceDefault.TextSuggestionsPopupWindow" parent="Widget.Quantum.TextSuggestionsPopupWindow"/>
+    <style name="Widget.DeviceDefault.TextView.ListSeparator" parent="Widget.Quantum.TextView.ListSeparator"/>
+    <style name="Widget.DeviceDefault.TimePicker" parent="Widget.Quantum.TimePicker"/>
+    <style name="Widget.DeviceDefault.Light" parent="Widget.Quantum.Light"/>
+    <style name="Widget.DeviceDefault.Light.Button" parent="Widget.Quantum.Light.Button"/>
+    <style name="Widget.DeviceDefault.Light.Button.Small" parent="Widget.Quantum.Light.Button.Small"/>
+    <style name="Widget.DeviceDefault.Light.Button.Inset" parent="Widget.Quantum.Light.Button.Inset"/>
+    <style name="Widget.DeviceDefault.Light.Button.Toggle" parent="Widget.Quantum.Light.Button.Toggle"/>
+    <style name="Widget.DeviceDefault.Light.TextView" parent="Widget.Quantum.Light.TextView"/>
+    <style name="Widget.DeviceDefault.Light.CheckedTextView" parent="Widget.Quantum.Light.CheckedTextView"/>
+    <style name="Widget.DeviceDefault.Light.AutoCompleteTextView" parent="Widget.Quantum.Light.AutoCompleteTextView"/>
+    <style name="Widget.DeviceDefault.Light.CompoundButton.CheckBox" parent="Widget.Quantum.Light.CompoundButton.CheckBox"/>
+    <style name="Widget.DeviceDefault.Light.ListView.DropDown" parent="Widget.Quantum.Light.ListView.DropDown"/>
+    <style name="Widget.DeviceDefault.Light.EditText" parent="Widget.Quantum.Light.EditText"/>
+    <style name="Widget.DeviceDefault.Light.ExpandableListView" parent="Widget.Quantum.Light.ExpandableListView"/>
+    <style name="Widget.DeviceDefault.Light.FastScroll" parent="Widget.Quantum.Light.FastScroll"/>
+    <style name="Widget.DeviceDefault.Light.FragmentBreadCrumbs" parent="Widget.Quantum.Light.FragmentBreadCrumbs"/>
+    <style name="Widget.DeviceDefault.Light.GridView" parent="Widget.Quantum.Light.GridView"/>
+    <style name="Widget.DeviceDefault.Light.ImageButton" parent="Widget.Quantum.Light.ImageButton"/>
+    <style name="Widget.DeviceDefault.Light.ListView" parent="Widget.Quantum.Light.ListView"/>
+    <style name="Widget.DeviceDefault.Light.PopupWindow" parent="Widget.Quantum.Light.PopupWindow"/>
+    <style name="Widget.DeviceDefault.Light.ProgressBar" parent="Widget.Quantum.Light.ProgressBar"/>
+    <style name="Widget.DeviceDefault.Light.ProgressBar.Horizontal" parent="Widget.Quantum.Light.ProgressBar.Horizontal"/>
+    <style name="Widget.DeviceDefault.Light.ProgressBar.Small" parent="Widget.Quantum.Light.ProgressBar.Small"/>
+    <style name="Widget.DeviceDefault.Light.ProgressBar.Small.Title" parent="Widget.Quantum.Light.ProgressBar.Small.Title"/>
+    <style name="Widget.DeviceDefault.Light.ProgressBar.Large" parent="Widget.Quantum.Light.ProgressBar.Large"/>
+    <style name="Widget.DeviceDefault.Light.ProgressBar.Inverse" parent="Widget.Quantum.Light.ProgressBar.Inverse"/>
+    <style name="Widget.DeviceDefault.Light.ProgressBar.Small.Inverse" parent="Widget.Quantum.Light.ProgressBar.Small.Inverse"/>
+    <style name="Widget.DeviceDefault.Light.ProgressBar.Large.Inverse" parent="Widget.Quantum.Light.ProgressBar.Large.Inverse"/>
+    <style name="Widget.DeviceDefault.Light.SeekBar" parent="Widget.Quantum.Light.SeekBar"/>
+    <style name="Widget.DeviceDefault.Light.RatingBar" parent="Widget.Quantum.Light.RatingBar"/>
+    <style name="Widget.DeviceDefault.Light.RatingBar.Indicator" parent="Widget.Quantum.Light.RatingBar.Indicator"/>
+    <style name="Widget.DeviceDefault.Light.RatingBar.Small" parent="Widget.Quantum.Light.RatingBar.Small"/>
+    <style name="Widget.DeviceDefault.Light.CompoundButton.RadioButton" parent="Widget.Quantum.Light.CompoundButton.RadioButton"/>
+    <style name="Widget.DeviceDefault.Light.ScrollView" parent="Widget.Quantum.Light.ScrollView"/>
+    <style name="Widget.DeviceDefault.Light.HorizontalScrollView" parent="Widget.Quantum.Light.HorizontalScrollView"/>
+    <style name="Widget.DeviceDefault.Light.Spinner" parent="Widget.Quantum.Light.Spinner"/>
+    <style name="Widget.DeviceDefault.Light.CompoundButton.Star" parent="Widget.Quantum.Light.CompoundButton.Star"/>
+    <style name="Widget.DeviceDefault.Light.TabWidget" parent="Widget.Quantum.Light.TabWidget"/>
+    <style name="Widget.DeviceDefault.Light.WebTextView" parent="Widget.Quantum.Light.WebTextView"/>
+    <style name="Widget.DeviceDefault.Light.WebView" parent="Widget.Quantum.Light.WebView"/>
+    <style name="Widget.DeviceDefault.Light.DropDownItem" parent="Widget.Quantum.Light.DropDownItem"/>
+    <style name="Widget.DeviceDefault.Light.DropDownItem.Spinner" parent="Widget.Quantum.Light.DropDownItem.Spinner"/>
+    <style name="Widget.DeviceDefault.Light.TextView.SpinnerItem" parent="Widget.Quantum.Light.TextView.SpinnerItem"/>
+    <style name="Widget.DeviceDefault.Light.ListPopupWindow" parent="Widget.Quantum.Light.ListPopupWindow"/>
+    <style name="Widget.DeviceDefault.Light.PopupMenu" parent="Widget.Quantum.Light.PopupMenu"/>
+    <style name="Widget.DeviceDefault.Light.Tab" parent="Widget.Quantum.Light.Tab"/>
+    <style name="Widget.DeviceDefault.Light.CalendarView" parent="Widget.Quantum.Light.CalendarView"/>
+    <style name="Widget.DeviceDefault.Light.Button.Borderless.Small" parent="Widget.Quantum.Light.Button.Borderless.Small"/>
+    <style name="Widget.DeviceDefault.Light.ActionButton" parent="Widget.Quantum.Light.ActionButton"/>
+    <style name="Widget.DeviceDefault.Light.ActionButton.Overflow" parent="Widget.Quantum.Light.ActionButton.Overflow"/>
+    <style name="Widget.DeviceDefault.Light.ActionMode" parent="Widget.Quantum.Light.ActionMode"/>
+    <style name="Widget.DeviceDefault.Light.ActionButton.CloseMode" parent="Widget.Quantum.Light.ActionButton.CloseMode"/>
+    <style name="Widget.DeviceDefault.Light.ActionBar" parent="Widget.Quantum.Light.ActionBar"/>
+    <style name="Widget.DeviceDefault.Light.ActionBar.TabView" parent="Widget.Quantum.Light.ActionBar.TabView"/>
+    <style name="Widget.DeviceDefault.Light.ActionBar.TabText" parent="Widget.Quantum.Light.ActionBar.TabText"/>
+    <style name="Widget.DeviceDefault.Light.ActionBar.TabBar" parent="Widget.Quantum.Light.ActionBar.TabBar"/>
+    <style name="Widget.DeviceDefault.Light.ActionBar.Solid" parent="Widget.Quantum.Light.ActionBar.Solid"/>
+    <!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
+    <style name="Widget.DeviceDefault.Light.ActionBar.Solid.Inverse" parent="Widget.Holo.Light.ActionBar.Solid.Inverse"/>
+    <!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
+    <style name="Widget.DeviceDefault.Light.ActionBar.TabBar.Inverse" parent="Widget.Holo.Light.ActionBar.TabBar.Inverse"/>
+    <!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
+    <style name="Widget.DeviceDefault.Light.ActionBar.TabView.Inverse" parent="Widget.Holo.Light.ActionBar.TabView.Inverse"/>
+    <!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
+    <style name="Widget.DeviceDefault.Light.ActionBar.TabText.Inverse" parent="Widget.Holo.Light.ActionBar.TabText.Inverse"/>
+    <!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
+    <style name="Widget.DeviceDefault.Light.ActionMode.Inverse" parent="Widget.Holo.Light.ActionMode.Inverse"/>
+    <style name="Widget.DeviceDefault.Light.AbsListView" parent="Widget.Quantum.Light.AbsListView"/>
+    <style name="Widget.DeviceDefault.Light.Spinner.DropDown.ActionBar" parent="Widget.Quantum.Light.Spinner.DropDown.ActionBar"/>
+    <style name="Widget.DeviceDefault.Light.PopupWindow.ActionMode" parent="Widget.Quantum.Light.PopupWindow.ActionMode"/>
+    <style name="Widget.DeviceDefault.Light.Button.Borderless" parent="Widget.Quantum.Light.Button.Borderless"/>
+    <style name="Widget.DeviceDefault.Light.DatePicker" parent="Widget.Quantum.Light.DatePicker"/>
+    <style name="Widget.DeviceDefault.Light.ExpandableListView.White" parent="Widget.Quantum.Light.ExpandableListView.White"/>
+    <style name="Widget.DeviceDefault.Light.Gallery" parent="Widget.Quantum.Light.Gallery"/>
+    <style name="Widget.DeviceDefault.Light.GestureOverlayView" parent="Widget.Quantum.Light.GestureOverlayView"/>
+    <style name="Widget.DeviceDefault.Light.ImageWell" parent="Widget.Quantum.Light.ImageWell"/>
+    <style name="Widget.DeviceDefault.Light.ListView.White" parent="Widget.Quantum.Light.ListView.White"/>
+    <style name="Widget.DeviceDefault.Light.NumberPicker" parent="Widget.Quantum.Light.NumberPicker"/>
+    <style name="Widget.DeviceDefault.Light.Spinner.DropDown" parent="Widget.Quantum.Light.Spinner.DropDown"/>
+    <style name="Widget.DeviceDefault.Light.TextView.ListSeparator" parent="Widget.Quantum.Light.TextView.ListSeparator"/>
+    <style name="Widget.DeviceDefault.Light.TimePicker" parent="Widget.Quantum.Light.TimePicker"/>
+    <style name="Widget.DeviceDefault.Light.TextSuggestionsPopupWindow" parent="Widget.Quantum.Light.TextSuggestionsPopupWindow"/>
 
 
     <!-- Text Appearance Styles -->
-    <style name="TextAppearance.DeviceDefault" parent="TextAppearance.Holo" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Inverse" parent="TextAppearance.Holo.Inverse" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Large" parent="TextAppearance.Holo.Large" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Large.Inverse" parent="TextAppearance.Holo.Large.Inverse" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Medium" parent="TextAppearance.Holo.Medium" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Medium.Inverse" parent="TextAppearance.Holo.Medium.Inverse" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Small" parent="TextAppearance.Holo.Small" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Small.Inverse" parent="TextAppearance.Holo.Small.Inverse" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.SearchResult.Title" parent="TextAppearance.Holo.SearchResult.Title" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.SearchResult.Subtitle" parent="TextAppearance.Holo.SearchResult.Subtitle" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget" parent="TextAppearance.Holo.Widget" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.Button" parent="TextAppearance.Holo.Widget.Button" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.IconMenu.Item" parent="TextAppearance.Holo.Widget.IconMenu.Item" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.TabWidget" parent="TextAppearance.Holo.Widget.TabWidget" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.TextView" parent="TextAppearance.Holo.Widget.TextView" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.TextView.PopupMenu" parent="TextAppearance.Holo.Widget.TextView.PopupMenu" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.DropDownHint" parent="TextAppearance.Holo.Widget.DropDownHint" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.DropDownItem" parent="TextAppearance.Holo.Widget.DropDownItem" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.TextView.SpinnerItem" parent="TextAppearance.Holo.Widget.TextView.SpinnerItem" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.EditText" parent="TextAppearance.Holo.Widget.EditText" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.PopupMenu" parent="TextAppearance.Holo.Widget.PopupMenu" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.PopupMenu.Large" parent="TextAppearance.Holo.Widget.PopupMenu.Large" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.PopupMenu.Small" parent="TextAppearance.Holo.Widget.PopupMenu.Small" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Title" parent="TextAppearance.Holo.Widget.ActionBar.Title" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle" parent="TextAppearance.Holo.Widget.ActionBar.Subtitle" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Title" parent="TextAppearance.Holo.Widget.ActionMode.Title" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle" parent="TextAppearance.Holo.Widget.ActionMode.Subtitle" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.WindowTitle" parent="TextAppearance.Holo.WindowTitle" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.DialogWindowTitle" parent="TextAppearance.Holo.DialogWindowTitle" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Title.Inverse" parent="TextAppearance.Holo.Widget.ActionBar.Title.Inverse" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle.Inverse" parent="TextAppearance.Holo.Widget.ActionBar.Subtitle.Inverse" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Title.Inverse" parent="TextAppearance.Holo.Widget.ActionMode.Title.Inverse" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle.Inverse" parent="TextAppearance.Holo.Widget.ActionMode.Subtitle.Inverse" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Menu" parent="TextAppearance.Holo.Widget.ActionBar.Menu" >
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Light" parent="TextAppearance.Holo.Light">
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Light.Inverse" parent="TextAppearance.Holo.Light.Inverse">
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Light.Large" parent="TextAppearance.Holo.Light.Large">
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Light.Large.Inverse" parent="TextAppearance.Holo.Light.Large.Inverse">
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Light.Medium" parent="TextAppearance.Holo.Light.Medium">
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Light.Medium.Inverse" parent="TextAppearance.Holo.Light.Medium.Inverse">
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Light.SearchResult.Subtitle" parent="TextAppearance.Holo.Light.SearchResult.Subtitle">
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Light.SearchResult.Title" parent="TextAppearance.Holo.Light.SearchResult.Title">
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Light.Small" parent="TextAppearance.Holo.Light.Small">
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Light.Small.Inverse" parent="TextAppearance.Holo.Light.Small.Inverse">
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Light.Widget.Button" parent="TextAppearance.Holo.Light.Widget.Button">
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Light.Widget.PopupMenu.Large" parent="TextAppearance.Holo.Light.Widget.PopupMenu.Large">
-
-    </style>
-    <style name="TextAppearance.DeviceDefault.Light.Widget.PopupMenu.Small" parent="TextAppearance.Holo.Light.Widget.PopupMenu.Small">
-
-    </style>
+    <style name="TextAppearance.DeviceDefault" parent="TextAppearance.Quantum"/>
+    <style name="TextAppearance.DeviceDefault.Inverse" parent="TextAppearance.Quantum.Inverse"/>
+    <style name="TextAppearance.DeviceDefault.Large" parent="TextAppearance.Quantum.Large"/>
+    <style name="TextAppearance.DeviceDefault.Large.Inverse" parent="TextAppearance.Quantum.Large.Inverse"/>
+    <style name="TextAppearance.DeviceDefault.Medium" parent="TextAppearance.Quantum.Medium"/>
+    <style name="TextAppearance.DeviceDefault.Medium.Inverse" parent="TextAppearance.Quantum.Medium.Inverse"/>
+    <style name="TextAppearance.DeviceDefault.Small" parent="TextAppearance.Quantum.Small"/>
+    <style name="TextAppearance.DeviceDefault.Small.Inverse" parent="TextAppearance.Quantum.Small.Inverse"/>
+    <style name="TextAppearance.DeviceDefault.SearchResult.Title" parent="TextAppearance.Quantum.SearchResult.Title"/>
+    <style name="TextAppearance.DeviceDefault.SearchResult.Subtitle" parent="TextAppearance.Quantum.SearchResult.Subtitle"/>
+    <style name="TextAppearance.DeviceDefault.Widget" parent="TextAppearance.Quantum.Widget"/>
+    <style name="TextAppearance.DeviceDefault.Widget.Button" parent="TextAppearance.Quantum.Widget.Button"/>
+    <style name="TextAppearance.DeviceDefault.Widget.IconMenu.Item" parent="TextAppearance.Quantum.Widget.IconMenu.Item"/>
+    <style name="TextAppearance.DeviceDefault.Widget.TabWidget" parent="TextAppearance.Quantum.Widget.TabWidget"/>
+    <style name="TextAppearance.DeviceDefault.Widget.TextView" parent="TextAppearance.Quantum.Widget.TextView"/>
+    <style name="TextAppearance.DeviceDefault.Widget.TextView.PopupMenu" parent="TextAppearance.Quantum.Widget.TextView.PopupMenu"/>
+    <style name="TextAppearance.DeviceDefault.Widget.DropDownHint" parent="TextAppearance.Quantum.Widget.DropDownHint"/>
+    <style name="TextAppearance.DeviceDefault.Widget.DropDownItem" parent="TextAppearance.Quantum.Widget.DropDownItem"/>
+    <style name="TextAppearance.DeviceDefault.Widget.TextView.SpinnerItem" parent="TextAppearance.Quantum.Widget.TextView.SpinnerItem"/>
+    <style name="TextAppearance.DeviceDefault.Widget.EditText" parent="TextAppearance.Quantum.Widget.EditText"/>
+    <style name="TextAppearance.DeviceDefault.Widget.PopupMenu" parent="TextAppearance.Quantum.Widget.PopupMenu"/>
+    <style name="TextAppearance.DeviceDefault.Widget.PopupMenu.Large" parent="TextAppearance.Quantum.Widget.PopupMenu.Large"/>
+    <style name="TextAppearance.DeviceDefault.Widget.PopupMenu.Small" parent="TextAppearance.Quantum.Widget.PopupMenu.Small"/>
+    <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Title" parent="TextAppearance.Quantum.Widget.ActionBar.Title"/>
+    <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle" parent="TextAppearance.Quantum.Widget.ActionBar.Subtitle"/>
+    <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Title" parent="TextAppearance.Quantum.Widget.ActionMode.Title"/>
+    <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle" parent="TextAppearance.Quantum.Widget.ActionMode.Subtitle"/>
+    <style name="TextAppearance.DeviceDefault.WindowTitle" parent="TextAppearance.Quantum.WindowTitle"/>
+    <style name="TextAppearance.DeviceDefault.DialogWindowTitle" parent="TextAppearance.Quantum.DialogWindowTitle"/>
+    <!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
+    <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Title.Inverse" parent="TextAppearance.Quantum.Widget.ActionBar.Title.Inverse"/>
+    <!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
+    <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle.Inverse" parent="TextAppearance.Quantum.Widget.ActionBar.Subtitle.Inverse"/>
+    <!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
+    <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Title.Inverse" parent="TextAppearance.Quantum.Widget.ActionMode.Title.Inverse"/>
+    <!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
+    <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle.Inverse" parent="TextAppearance.Quantum.Widget.ActionMode.Subtitle.Inverse"/>
+    <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Menu" parent="TextAppearance.Quantum.Widget.ActionBar.Menu"/>
+    <style name="TextAppearance.DeviceDefault.Light" parent="TextAppearance.Quantum.Light"/>
+    <style name="TextAppearance.DeviceDefault.Light.Inverse" parent="TextAppearance.Quantum.Light.Inverse"/>
+    <style name="TextAppearance.DeviceDefault.Light.Large" parent="TextAppearance.Quantum.Light.Large"/>
+    <style name="TextAppearance.DeviceDefault.Light.Large.Inverse" parent="TextAppearance.Quantum.Light.Large.Inverse"/>
+    <style name="TextAppearance.DeviceDefault.Light.Medium" parent="TextAppearance.Quantum.Light.Medium"/>
+    <style name="TextAppearance.DeviceDefault.Light.Medium.Inverse" parent="TextAppearance.Quantum.Light.Medium.Inverse"/>
+    <style name="TextAppearance.DeviceDefault.Light.SearchResult.Subtitle" parent="TextAppearance.Quantum.Light.SearchResult.Subtitle"/>
+    <style name="TextAppearance.DeviceDefault.Light.SearchResult.Title" parent="TextAppearance.Quantum.Light.SearchResult.Title"/>
+    <style name="TextAppearance.DeviceDefault.Light.Small" parent="TextAppearance.Quantum.Light.Small"/>
+    <style name="TextAppearance.DeviceDefault.Light.Small.Inverse" parent="TextAppearance.Quantum.Light.Small.Inverse"/>
+    <style name="TextAppearance.DeviceDefault.Light.Widget.Button" parent="TextAppearance.Quantum.Light.Widget.Button"/>
+    <style name="TextAppearance.DeviceDefault.Light.Widget.PopupMenu.Large" parent="TextAppearance.Quantum.Light.Widget.PopupMenu.Large"/>
+    <style name="TextAppearance.DeviceDefault.Light.Widget.PopupMenu.Small" parent="TextAppearance.Quantum.Light.Widget.PopupMenu.Small"/>
 
 
     <!-- Preference Styles -->
-    <style name="Preference.DeviceDefault" parent="Preference.Holo">
-
-    </style>
-    <style name="Preference.DeviceDefault.Category" parent="Preference.Holo.Category">
-
-    </style>
-    <style name="Preference.DeviceDefault.CheckBoxPreference" parent="Preference.Holo.CheckBoxPreference">
-
-    </style>
-    <style name="Preference.DeviceDefault.DialogPreference" parent="Preference.Holo.DialogPreference">
-
-    </style>
-    <style name="Preference.DeviceDefault.DialogPreference.EditTextPreference" parent="Preference.Holo.DialogPreference.EditTextPreference">
-
-    </style>
-    <style name="Preference.DeviceDefault.DialogPreference.YesNoPreference" parent="Preference.Holo.DialogPreference.YesNoPreference">
-
-    </style>
-    <style name="Preference.DeviceDefault.Information" parent="Preference.Holo.Information">
-
-    </style>
-    <style name="Preference.DeviceDefault.PreferenceScreen" parent="Preference.Holo.PreferenceScreen">
-
-    </style>
-    <style name="Preference.DeviceDefault.RingtonePreference" parent="Preference.Holo.RingtonePreference">
-
-    </style>
-    <style name="Preference.DeviceDefault.SwitchPreference" parent="Preference.Holo.SwitchPreference">
-
-    </style>
+    <style name="Preference.DeviceDefault" parent="Preference.Quantum"/>
+    <style name="Preference.DeviceDefault.Category" parent="Preference.Quantum.Category"/>
+    <style name="Preference.DeviceDefault.CheckBoxPreference" parent="Preference.Quantum.CheckBoxPreference"/>
+    <style name="Preference.DeviceDefault.DialogPreference" parent="Preference.Quantum.DialogPreference"/>
+    <style name="Preference.DeviceDefault.DialogPreference.EditTextPreference" parent="Preference.Quantum.DialogPreference.EditTextPreference"/>
+    <style name="Preference.DeviceDefault.DialogPreference.YesNoPreference" parent="Preference.Quantum.DialogPreference.YesNoPreference"/>
+    <style name="Preference.DeviceDefault.Information" parent="Preference.Quantum.Information"/>
+    <style name="Preference.DeviceDefault.PreferenceScreen" parent="Preference.Quantum.PreferenceScreen"/>
+    <style name="Preference.DeviceDefault.RingtonePreference" parent="Preference.Quantum.RingtonePreference"/>
+    <style name="Preference.DeviceDefault.SwitchPreference" parent="Preference.Quantum.SwitchPreference"/>
 
 
     <!-- AlertDialog Styles -->
-    <style name="AlertDialog.DeviceDefault" parent="AlertDialog.Holo">
-
-    </style>
-    <style name="AlertDialog.DeviceDefault.Light" parent="AlertDialog.Holo.Light" >
-
-    </style>
+    <style name="AlertDialog.DeviceDefault" parent="AlertDialog.Quantum"/>
+    <style name="AlertDialog.DeviceDefault.Light" parent="AlertDialog.Quantum.Light"/>
 
     <!-- Animation Styles -->
-    <style name="Animation.DeviceDefault.Activity" parent="Animation.Holo.Activity">
-
-    </style>
-    <style name="Animation.DeviceDefault.Dialog" parent="Animation.Holo.Dialog">
-
-    </style>
+    <style name="Animation.DeviceDefault.Activity" parent="Animation.Quantum.Activity"/>
+    <style name="Animation.DeviceDefault.Dialog" parent="Animation.Quantum.Dialog"/>
 
 
     <!-- DialogWindowTitle Styles -->
-    <style name="DialogWindowTitle.DeviceDefault" parent="DialogWindowTitle.Holo">
-
-    </style>
-    <style name="DialogWindowTitle.DeviceDefault.Light" parent="DialogWindowTitle.Holo.Light">
-
-    </style>
+    <style name="DialogWindowTitle.DeviceDefault" parent="DialogWindowTitle.Quantum"/>
+    <style name="DialogWindowTitle.DeviceDefault.Light" parent="DialogWindowTitle.Quantum.Light"/>
 
 
     <!-- WindowTitle Styles -->
-    <style name="WindowTitle.DeviceDefault" parent="WindowTitle.Holo">
-
-    </style>
-    <style name="WindowTitleBackground.DeviceDefault" parent="WindowTitleBackground.Holo">
-
-    </style>
+    <style name="WindowTitle.DeviceDefault" parent="WindowTitle.Quantum"/>
+    <style name="WindowTitleBackground.DeviceDefault" parent="WindowTitleBackground.Quantum"/>
 
 
     <!-- Other Styles -->
-    <style name="DeviceDefault.ButtonBar" parent="Holo.ButtonBar" >
+    <style name="DeviceDefault.ButtonBar" parent="Widget.Quantum.ButtonBar"/>
+    <style name="DeviceDefault.ButtonBar.AlertDialog" parent="Widget.Quantum.ButtonBar.AlertDialog"/>
+    <style name="DeviceDefault.SegmentedButton" parent="Widget.Quantum.SegmentedButton"/>
+    <style name="DeviceDefault.Light.ButtonBar" parent="Widget.Quantum.Light.ButtonBar"/>
+    <style name="DeviceDefault.Light.ButtonBar.AlertDialog" parent="Widget.Quantum.Light.ButtonBar.AlertDialog"/>
+    <style name="DeviceDefault.Light.SegmentedButton" parent="Widget.Quantum.Light.SegmentedButton"/>
 
-    </style>
-    <style name="DeviceDefault.ButtonBar.AlertDialog" parent="Holo.ButtonBar.AlertDialog" >
+    <style name="Widget.DeviceDefault.MediaRouteButton" parent="Widget.Quantum.MediaRouteButton" />
+    <style name="Widget.DeviceDefault.Light.MediaRouteButton" parent="Widget.Quantum.Light.MediaRouteButton" />
 
-    </style>
-    <style name="DeviceDefault.SegmentedButton" parent="Holo.SegmentedButton" >
-
-    </style>
-    <style name="DeviceDefault.Light.ButtonBar" parent="Holo.Light.ButtonBar" >
-
-    </style>
-    <style name="DeviceDefault.Light.ButtonBar.AlertDialog" parent="Holo.Light.ButtonBar.AlertDialog" >
-
-    </style>
-    <style name="DeviceDefault.Light.SegmentedButton" parent="Holo.Light.SegmentedButton" >
-
-    </style>
-
-    <style name="Widget.DeviceDefault.MediaRouteButton" parent="Widget.Holo.MediaRouteButton" />
-    <style name="Widget.DeviceDefault.Light.MediaRouteButton" parent="Widget.Holo.Light.MediaRouteButton" />
-
-    <style name="TextAppearance.DeviceDefault.TimePicker.TimeLabel" parent="TextAppearance.Holo.TimePicker.TimeLabel">
-    </style>
-
-    <style name="TextAppearance.DeviceDefault.Light.TimePicker.TimeLabel" parent="TextAppearance.Holo.Light.TimePicker.TimeLabel">
-    </style>
-
-    <style name="TextAppearance.DeviceDefault.TimePicker.AmPmLabel" parent="TextAppearance.Holo.TimePicker.AmPmLabel">
-    </style>
-
-    <style name="TextAppearance.DeviceDefault.Light.TimePicker.AmPmLabel" parent="TextAppearance.Holo.Light.TimePicker.AmPmLabel">
-    </style>
-
-    <style name="Theme.DeviceDefault.Dialog.TimePicker" parent="Theme.Holo.Dialog.TimePicker">
-    </style>
-
-    <style name="Theme.DeviceDefault.Light.Dialog.TimePicker" parent="Theme.Holo.Light.Dialog.TimePicker">
-    </style>
-
+    <style name="TextAppearance.DeviceDefault.TimePicker.TimeLabel" parent="TextAppearance.Quantum.TimePicker.TimeLabel"/>
+    <style name="TextAppearance.DeviceDefault.Light.TimePicker.TimeLabel" parent="TextAppearance.Quantum.Light.TimePicker.TimeLabel"/>
+    <style name="TextAppearance.DeviceDefault.TimePicker.AmPmLabel" parent="TextAppearance.Quantum.TimePicker.AmPmLabel"/>
+    <style name="TextAppearance.DeviceDefault.Light.TimePicker.AmPmLabel" parent="TextAppearance.Quantum.Light.TimePicker.AmPmLabel"/>
+    <style name="Theme.DeviceDefault.Dialog.TimePicker" parent="Theme.Quantum.Dialog.TimePicker"/>
+    <style name="Theme.DeviceDefault.Light.Dialog.TimePicker" parent="Theme.Quantum.Light.Dialog.TimePicker"/>
 </resources>
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index 2020fea..84a1ca4 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -277,20 +277,36 @@
         <item name="textSize">@dimen/action_bar_title_text_size_quantum</item>
     </style>
 
+    <style name="TextAppearance.Quantum.Widget.ActionMode.Title.Inverse" parent="TextAppearance.Quantum.Medium.Inverse">
+        <item name="textSize">@dimen/action_bar_title_text_size_quantum</item>
+    </style>
+
     <style name="TextAppearance.Quantum.Widget.ActionMode.Subtitle" parent="TextAppearance.Quantum.Small">
         <item name="textSize">@dimen/action_bar_subtitle_text_size_quantum</item>
     </style>
 
+    <style name="TextAppearance.Quantum.Widget.ActionMode.Subtitle.Inverse" parent="TextAppearance.Quantum.Small.Inverse">
+        <item name="textSize">@dimen/action_bar_subtitle_text_size_quantum</item>
+    </style>
+
     <!-- Text styles with no light versions -->
 
     <style name="TextAppearance.Quantum.Widget.ActionBar.Title" parent="TextAppearance.Quantum.Medium">
         <item name="textSize">@dimen/action_bar_title_text_size_quantum</item>
     </style>
 
+    <style name="TextAppearance.Quantum.Widget.ActionBar.Title.Inverse" parent="TextAppearance.Quantum.Medium.Inverse">
+        <item name="textSize">@dimen/action_bar_title_text_size_quantum</item>
+    </style>
+
     <style name="TextAppearance.Quantum.Widget.ActionBar.Subtitle" parent="TextAppearance.Quantum.Small">
         <item name="textSize">@dimen/action_bar_subtitle_text_size_quantum</item>
     </style>
 
+    <style name="TextAppearance.Quantum.Widget.ActionBar.Subtitle.Inverse" parent="TextAppearance.Quantum.Small.Inverse">
+        <item name="textSize">@dimen/action_bar_subtitle_text_size_quantum</item>
+    </style>
+
     <style name="TextAppearance.Quantum.Widget.ActionBar.Menu" parent="TextAppearance.Quantum.Small">
         <item name="fontFamily">@string/font_family_menu_quantum</item>
         <item name="textSize">@dimen/text_size_menu_quantum</item>>
@@ -298,6 +314,13 @@
         <item name="textAllCaps">@bool/config_actionMenuItemAllCaps</item>
     </style>
 
+    <style name="TextAppearance.Quantum.Widget.ActionBar.Menu.Inverse" parent="TextAppearance.Quantum.Small.Inverse">
+        <item name="fontFamily">@string/font_family_menu_quantum</item>
+        <item name="textSize">@dimen/text_size_menu_quantum</item>>
+        <item name="textColor">?attr/actionMenuTextColor</item>
+        <item name="textAllCaps">@bool/config_actionMenuItemAllCaps</item>
+    </style>
+
     <style name="TextAppearance.Quantum.WindowTitle">
         <item name="textColor">?attr/textColorPrimary</item>
         <item name="fontFamily">@string/font_family_headline_quantum</item>
@@ -607,8 +630,8 @@
     </style>
 
     <style name="Widget.Quantum.RatingBar" parent="Widget.RatingBar">
-        <item name="progressDrawable">@drawable/ratingbar_full_holo_dark</item>
-        <item name="indeterminateDrawable">@drawable/ratingbar_full_holo_dark</item>
+        <item name="progressDrawable">@drawable/ratingbar_full_quantum</item>
+        <item name="indeterminateDrawable">@drawable/ratingbar_full_quantum</item>
     </style>
 
     <style name="Widget.Quantum.RatingBar.Indicator" parent="Widget.RatingBar.Indicator">
@@ -654,7 +677,7 @@
         <item name="showDividers">middle</item>
         <item name="dividerPadding">8dip</item>
         <item name="measureWithLargestChild">true</item>
-        <item name="tabLayout">@layout/tab_indicator_holo</item>
+        <item name="tabLayout">@layout/tab_indicator_quantum</item>
     </style>
 
     <style name="Widget.Quantum.Tab" parent="Widget.Quantum.ActionBar.TabView">
@@ -708,7 +731,7 @@
     </style>
 
     <style name="Widget.Quantum.ActionButton.CloseMode">
-        <item name="background">@drawable/btn_cab_done_holo_dark</item>
+        <item name="background">@drawable/btn_cab_done_quantum</item>
     </style>
 
     <style name="Widget.Quantum.ActionButton.Overflow">
@@ -745,8 +768,8 @@
         <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
         <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
         <item name="background">@drawable/ab_transparent_quantum</item>
-        <item name="backgroundStacked">@drawable/ab_stacked_transparent_dark_holo</item>
-        <item name="backgroundSplit">@drawable/ab_bottom_transparent_dark_holo</item>
+        <item name="backgroundStacked">@drawable/ab_stacked_transparent_quantum</item>
+        <item name="backgroundSplit">@drawable/ab_bottom_transparent_quantum</item>
         <item name="divider">?attr/dividerVertical</item>
         <item name="progressBarStyle">@style/Widget.Quantum.ProgressBar.Horizontal</item>
         <item name="indeterminateProgressStyle">@style/Widget.Quantum.ProgressBar</item>
@@ -757,9 +780,9 @@
     <style name="Widget.Quantum.ActionBar.Solid">
         <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
         <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
-        <item name="background">@drawable/ab_solid_dark_holo</item>
-        <item name="backgroundStacked">@drawable/ab_stacked_solid_dark_holo</item>
-        <item name="backgroundSplit">@drawable/ab_bottom_solid_dark_holo</item>
+        <item name="background">@drawable/ab_solid_quantum</item>
+        <item name="backgroundStacked">@drawable/ab_stacked_solid_quantum</item>
+        <item name="backgroundSplit">@drawable/ab_bottom_solid_quantum</item>
         <item name="divider">?attr/dividerVertical</item>
         <item name="progressBarStyle">@style/Widget.Quantum.ProgressBar.Horizontal</item>
         <item name="indeterminateProgressStyle">@style/Widget.Quantum.ProgressBar</item>
@@ -786,7 +809,7 @@
 
     <style name="Widget.Quantum.MediaRouteButton">
         <item name="background">?attr/selectableItemBackground</item>
-        <item name="externalRouteEnabledDrawable">@drawable/ic_media_route_holo_dark</item>
+        <item name="externalRouteEnabledDrawable">@drawable/ic_media_route_quantum</item>
         <item name="minWidth">56dp</item>
         <item name="minHeight">48dp</item>
         <item name="focusable">true</item>
@@ -873,7 +896,7 @@
     <style name="Widget.Quantum.Light.DatePicker" parent="Widget.Quantum.DatePicker"/>
 
     <style name="Widget.Quantum.Light.ActivityChooserView" parent="Widget.Quantum.ActivityChooserView">
-        <item name="background">@drawable/ab_share_pack_holo_light</item>
+        <item name="background">@drawable/ab_share_pack_quantum</item>
     </style>
 
     <style name="Widget.Quantum.Light.ImageWell" parent="Widget.Quantum.ImageWell"/>
@@ -896,10 +919,7 @@
     <style name="Widget.Quantum.Light.ProgressBar.Large.Inverse" parent="Widget.Quantum.ProgressBar.Large.Inverse"/>
     <style name="Widget.Quantum.Light.SeekBar" parent="Widget.Quantum.SeekBar"/>
 
-    <style name="Widget.Quantum.Light.RatingBar" parent="Widget.RatingBar">
-        <item name="progressDrawable">@drawable/ratingbar_full_holo_light</item>
-        <item name="indeterminateDrawable">@drawable/ratingbar_full_holo_light</item>
-    </style>
+    <style name="Widget.Quantum.Light.RatingBar" parent="Widget.Quantum.RatingBar" />
 
     <style name="Widget.Quantum.Light.RatingBar.Indicator" parent="Widget.RatingBar.Indicator">
         <item name="progressDrawable">@drawable/ratingbar_holo_light</item>
@@ -968,15 +988,15 @@
     </style>
 
     <style name="Widget.Quantum.Light.ActionButton.CloseMode">
-        <item name="background">@drawable/btn_cab_done_holo_light</item>
+        <item name="background">@drawable/btn_cab_done_quantum</item>
     </style>
 
     <style name="Widget.Quantum.Light.ActionBar" parent="Widget.Quantum.ActionBar">
         <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
         <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
         <item name="background">@drawable/ab_transparent_quantum</item>
-        <item name="backgroundStacked">@drawable/ab_stacked_transparent_light_holo</item>
-        <item name="backgroundSplit">@drawable/ab_bottom_transparent_light_holo</item>
+        <item name="backgroundStacked">@drawable/ab_stacked_transparent_quantum</item>
+        <item name="backgroundSplit">@drawable/ab_bottom_transparent_quantum</item>
         <item name="homeAsUpIndicator">@drawable/ic_ab_back_quantum</item>
         <item name="progressBarStyle">@style/Widget.Quantum.Light.ProgressBar.Horizontal</item>
         <item name="indeterminateProgressStyle">@style/Widget.Quantum.Light.ProgressBar</item>
@@ -985,9 +1005,9 @@
     <style name="Widget.Quantum.Light.ActionBar.Solid">
         <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
         <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
-        <item name="background">@drawable/ab_solid_light_holo</item>
-        <item name="backgroundStacked">@drawable/ab_stacked_solid_light_holo</item>
-        <item name="backgroundSplit">@drawable/ab_bottom_solid_light_holo</item>
+        <item name="background">@drawable/ab_solid_quantum</item>
+        <item name="backgroundStacked">@drawable/ab_stacked_solid_quantum</item>
+        <item name="backgroundSplit">@drawable/ab_bottom_solid_quantum</item>
         <item name="divider">?attr/dividerVertical</item>
         <item name="progressBarStyle">@style/Widget.Quantum.Light.ProgressBar.Horizontal</item>
         <item name="indeterminateProgressStyle">@style/Widget.Quantum.Light.ProgressBar</item>
@@ -1002,7 +1022,7 @@
     <style name="Widget.Quantum.Light.FastScroll" parent="Widget.Quantum.FastScroll"/>
 
     <style name="Widget.Quantum.Light.MediaRouteButton" parent="Widget.Quantum.MediaRouteButton">
-        <item name="externalRouteEnabledDrawable">@drawable/ic_media_route_holo_light</item>
+        <item name="externalRouteEnabledDrawable">@drawable/ic_media_route_quantum</item>
     </style>
 
     <!-- Animation Styles -->
@@ -1024,13 +1044,13 @@
         <item name="bottomBright">?attr/colorBackground</item>
         <item name="bottomMedium">?attr/colorBackground</item>
         <item name="centerMedium">?attr/colorBackground</item>
-        <item name="layout">@layout/alert_dialog_holo</item>
-        <item name="listLayout">@layout/select_dialog_holo</item>
-        <item name="progressLayout">@layout/progress_dialog_holo</item>
-        <item name="horizontalProgressLayout">@layout/alert_dialog_progress_holo</item>
-        <item name="listItemLayout">@layout/select_dialog_item_holo</item>
-        <item name="multiChoiceItemLayout">@layout/select_dialog_multichoice_holo</item>
-        <item name="singleChoiceItemLayout">@layout/select_dialog_singlechoice_holo</item>
+        <item name="layout">@layout/alert_dialog_quantum</item>
+        <item name="listLayout">@layout/select_dialog_quantum</item>
+        <item name="progressLayout">@layout/progress_dialog_quantum</item>
+        <item name="horizontalProgressLayout">@layout/alert_dialog_progress_quantum</item>
+        <item name="listItemLayout">@layout/select_dialog_item_quantum</item>
+        <item name="multiChoiceItemLayout">@layout/select_dialog_multichoice_quantum</item>
+        <item name="singleChoiceItemLayout">@layout/select_dialog_singlechoice_quantum</item>
     </style>
 
     <style name="AlertDialog.Quantum.Light"/>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index fa84750..557dce24 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1622,6 +1622,7 @@
   <java-symbol type="string" name="enable_explore_by_touch_warning_message" />
   <java-symbol type="bool" name="config_powerDecoupleAutoSuspendModeFromDisplay" />
   <java-symbol type="bool" name="config_powerDecoupleInteractiveModeFromDisplay" />
+  <java-symbol type="string" name="config_customAdbPublicKeyActivity" />
 
   <java-symbol type="layout" name="resolver_list" />
   <java-symbol type="id" name="resolver_list" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 19556a1..0ce5094 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -32,24 +32,24 @@
  -->
 <resources>
 
-    <!-- The default theme for apps that target API level 14 and higher.
+    <!-- The default theme for apps that target API level XX and higher.
          <p>The DeviceDefault themes are aliases for a specific device’s native look and feel. The
          DeviceDefault theme family and widget style family offer ways for you to target your app
          to a device’s native theme with all device customizations intact.</p>
-         <p>For example, when you set your app's {@code targetSdkVersion} to 14 or higher, this
+         <p>For example, when you set your app's {@code targetSdkVersion} to XX or higher, this
          theme is applied to your application by default. As such, your app might appear with the
-         {@link #Theme_Holo Holo} styles on one device, but with a different set of styles on
+         {@link #Theme_Quantum Quantum} styles on one device, but with a different set of styles on
          another device. This is great if you want your app to fit with the device's native look and
          feel. If, however, you prefer to keep your UI style the same across all devices, you should
-         apply a specific theme such as {@link #Theme_Holo Holo} or one of your own design. For more
-         information, read <a
-         href="http://android-developers.blogspot.com/2012/01/holo-everywhere.html">Holo
+         apply a specific theme such as {@link #Theme_Quantum Quantum} or one of your own design.
+         For more information, read <a
+         href="http://android-developers.blogspot.com/20XX/XX/quantum-everywhere.html">Quantum
          Everywhere</a>.</p>
          <p>Styles used by the DeviceDefault theme are named using the convention
          Type.DeviceDefault.Etc (for example, {@code Widget.DeviceDefault.Button} and
          {@code TextAppearance.DeviceDefault.Widget.PopupMenu.Large}).</p>
           -->
-    <style name="Theme.DeviceDefault" parent="Theme.Holo" >
+    <style name="Theme.DeviceDefault" parent="Theme.Quantum" >
         <!-- Text styles -->
         <item name="textAppearance">@android:style/TextAppearance.DeviceDefault</item>
         <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Inverse</item>
@@ -210,29 +210,29 @@
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar -->
-    <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Holo.NoActionBar" >
+    <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Quantum.NoActionBar" >
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar.  This theme
          sets {@link android.R.attr#windowFullscreen} to true.  -->
-    <style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Holo.NoActionBar.Fullscreen" >
+    <style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Quantum.NoActionBar.Fullscreen" >
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
     extending in to overscan region.  This theme
     sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
     to true. -->
-    <style name="Theme.DeviceDefault.NoActionBar.Overscan" parent="Theme.Holo.NoActionBar.Overscan" >
+    <style name="Theme.DeviceDefault.NoActionBar.Overscan" parent="Theme.Quantum.NoActionBar.Overscan" >
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent
          system decor.  This theme sets {@link android.R.attr#windowTranslucentStatus} and
          {@link android.R.attr#windowTranslucentNavigation} to true. -->
-    <style name="Theme.DeviceDefault.NoActionBar.TranslucentDecor" parent="Theme.Holo.NoActionBar.TranslucentDecor" >
+    <style name="Theme.DeviceDefault.NoActionBar.TranslucentDecor" parent="Theme.Quantum.NoActionBar.TranslucentDecor" >
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
-    <style name="Theme.DeviceDefault.Light" parent="Theme.Holo.Light" >
+    <style name="Theme.DeviceDefault.Light" parent="Theme.Quantum.Light" >
         <!-- Text styles -->
         <item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Light</item>
         <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Light.Inverse</item>
@@ -387,29 +387,29 @@
         <item name="mediaRouteButtonStyle">@android:style/Widget.DeviceDefault.Light.MediaRouteButton</item>
     </style>
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
-    <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Holo.Light.NoActionBar" >
+    <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Quantum.Light.NoActionBar" >
     </style>
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
          This theme sets {@link android.R.attr#windowFullscreen} to true.  -->
-    <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Holo.Light.NoActionBar.Fullscreen" >
+    <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Quantum.Light.NoActionBar.Fullscreen" >
     </style>
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
     and extending in to overscan region.  This theme
     sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
     to true. -->
     <style name="Theme.DeviceDefault.Light.NoActionBar.Overscan"
-           parent="Theme.Holo.Light.NoActionBar.Overscan" >
+           parent="Theme.Quantum.Light.NoActionBar.Overscan" >
     </style>
     <!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent
          system decor.  This theme sets {@link android.R.attr#windowTranslucentStatus} and
          {@link android.R.attr#windowTranslucentNavigation} to true. -->
     <style name="Theme.DeviceDefault.Light.NoActionBar.TranslucentDecor"
-           parent="Theme.Holo.Light.NoActionBar.TranslucentDecor" >
+           parent="Theme.Quantum.Light.NoActionBar.TranslucentDecor" >
     </style>
     <!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
     floating (not fill the entire screen), and puts a frame around its contents. You can set this
     theme on an activity if you would like to make an activity that looks like a Dialog. -->
-    <style name="Theme.DeviceDefault.Dialog" parent="Theme.Holo.Dialog" >
+    <style name="Theme.DeviceDefault.Dialog" parent="Theme.Quantum.Dialog" >
         <item name="android:windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault</item>
         <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Dialog</item>
 
@@ -421,16 +421,16 @@
     </style>
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
     regular dialog. -->
-    <style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Holo.Dialog.MinWidth" >
+    <style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Quantum.Dialog.MinWidth" >
 
     </style>
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
-    <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Holo.Dialog.NoActionBar" >
+    <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Quantum.Dialog.NoActionBar" >
 
     </style>
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
     for a regular dialog. -->
-    <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Holo.Dialog.NoActionBar.MinWidth" >
+    <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Quantum.Dialog.NoActionBar.MinWidth" >
 
     </style>
 
@@ -453,7 +453,7 @@
     <!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
     floating (not fill the entire screen), and puts a frame around its contents. You can set this
     theme on an activity if you would like to make an activity that looks like a Dialog.-->
-    <style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Holo.Light.Dialog" >
+    <style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Quantum.Light.Dialog" >
         <item name="android:windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault.Light</item>
         <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Dialog</item>
 
@@ -465,16 +465,16 @@
     </style>
     <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a
     regular dialog. -->
-    <style name="Theme.DeviceDefault.Light.Dialog.MinWidth" parent="Theme.Holo.Light.Dialog.MinWidth" >
+    <style name="Theme.DeviceDefault.Light.Dialog.MinWidth" parent="Theme.Quantum.Light.Dialog.MinWidth" >
 
     </style>
      <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
-    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar" parent="Theme.Holo.Light.Dialog.NoActionBar" >
+    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar" parent="Theme.Quantum.Light.Dialog.NoActionBar" >
 
     </style>
     <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
     width for a regular dialog. -->
-    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Holo.Light.Dialog.NoActionBar.MinWidth" >
+    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Quantum.Light.Dialog.NoActionBar.MinWidth" >
 
     </style>
 
@@ -496,65 +496,65 @@
 
     <!-- DeviceDefault theme for a window that will be displayed either full-screen on smaller
     screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
-    <style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Holo.DialogWhenLarge" >
+    <style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Quantum.DialogWhenLarge" >
 
     </style>
     <!-- DeviceDefault theme for a window without an action bar that will be displayed either
     full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
     xlarge). -->
-    <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Holo.DialogWhenLarge.NoActionBar" >
+    <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Quantum.DialogWhenLarge.NoActionBar" >
 
     </style>
     <!-- DeviceDefault light theme for a window that will be displayed either full-screen on smaller
     screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
-    <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Holo.Light.DialogWhenLarge" >
+    <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Quantum.Light.DialogWhenLarge" >
 
     </style>
     <!-- DeviceDefault light theme for a window without an action bar that will be displayed either
     full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
     xlarge). -->
-    <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Holo.Light.DialogWhenLarge.NoActionBar" >
+    <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Quantum.Light.DialogWhenLarge.NoActionBar" >
 
     </style>
 
     <!-- DeviceDefault theme for a presentation window on a secondary display. -->
-    <style name="Theme.DeviceDefault.Dialog.Presentation" parent="Theme.Holo.Dialog.Presentation">
+    <style name="Theme.DeviceDefault.Dialog.Presentation" parent="Theme.Quantum.Dialog.Presentation">
     </style>
 
     <!-- DeviceDefault light theme for a presentation window on a secondary display. -->
-    <style name="Theme.DeviceDefault.Light.Dialog.Presentation" parent="Theme.Holo.Light.Dialog.Presentation">
+    <style name="Theme.DeviceDefault.Light.Dialog.Presentation" parent="Theme.Quantum.Light.Dialog.Presentation">
     </style>
 
     <!-- DeviceDefault theme for panel windows. This removes all extraneous window
     decorations, so you basically have an empty rectangle in which to place your content. It makes
     the window floating, with a transparent background, and turns off dimming behind the window. -->
-    <style name="Theme.DeviceDefault.Panel" parent="Theme.Holo.Panel" >
+    <style name="Theme.DeviceDefault.Panel" parent="Theme.Quantum.Panel" >
 
     </style>
     <!-- DeviceDefault light theme for panel windows. This removes all extraneous window
     decorations, so you basically have an empty rectangle in which to place your content. It makes
     the window floating, with a transparent background, and turns off dimming behind the window. -->
-    <style name="Theme.DeviceDefault.Light.Panel" parent="Theme.Holo.Light.Panel" >
+    <style name="Theme.DeviceDefault.Light.Panel" parent="Theme.Quantum.Light.Panel" >
 
     </style>
     <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
     behind them. -->
-    <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Holo.Wallpaper" >
+    <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Quantum.Wallpaper" >
 
     </style>
     <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
     behind them and without an action bar. -->
-    <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar" parent="Theme.Holo.Wallpaper.NoTitleBar" >
+    <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar" parent="Theme.Quantum.Wallpaper.NoTitleBar" >
 
     </style>
     <!-- DeviceDefault style for input methods, which is used by the
          {@link android.inputmethodservice.InputMethodService} class.-->
-    <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Holo.InputMethod" >
+    <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Quantum.InputMethod" >
 
     </style>
     <!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an
     inverse color profile. -->
-    <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Holo.Light.DarkActionBar" >
+    <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Quantum.Light.DarkActionBar" >
         <item name="android:actionBarStyle">@android:style/Widget.DeviceDefault.Light.ActionBar.Solid.Inverse</item>
 
         <item name="actionDropDownStyle">@android:style/Widget.DeviceDefault.Spinner.DropDown.ActionBar</item>
@@ -569,20 +569,20 @@
 
     </style>
 
-    <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Holo.Dialog.Alert">
+    <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Quantum.Dialog.Alert">
         <item name="windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault</item>
     </style>
-    <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Holo.Light.Dialog.Alert">
+    <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Quantum.Light.Dialog.Alert">
         <item name="windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault.Light</item>
     </style>
-    <style name="Theme.DeviceDefault.SearchBar" parent="Theme.Holo.SearchBar">
+    <style name="Theme.DeviceDefault.SearchBar" parent="Theme.Quantum.SearchBar">
 
     </style>
-    <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Holo.Light.SearchBar">
+    <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Quantum.Light.SearchBar">
 
     </style>
 
-    <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Holo.Dialog.NoFrame">
+    <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Quantum.Dialog.NoFrame">
     </style>
 
 </resources>
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index 24abd55..d39a1f8 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -476,7 +476,7 @@
         <item name="windowFullscreen">false</item>
         <item name="windowOverscan">false</item>
         <item name="windowIsFloating">false</item>
-        <item name="windowContentOverlay">@drawable/ab_solid_shadow_qntm</item>
+        <item name="windowContentOverlay">@drawable/ab_solid_shadow_quantum</item>
         <item name="windowShowWallpaper">false</item>
         <item name="windowTitleStyle">@style/WindowTitle.Quantum</item>
         <item name="windowTitleSize">25dip</item>
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 04f8009..e77564f 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -21,6 +21,7 @@
 import com.android.frameworks.coretests.R;
 import com.android.internal.content.PackageHelper;
 
+import android.app.PackageInstallObserver;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -31,6 +32,7 @@
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.IBinder;
@@ -117,12 +119,12 @@
         super.tearDown();
     }
 
-    private class PackageInstallObserver extends IPackageInstallObserver.Stub {
+    private class TestInstallObserver extends PackageInstallObserver {
         public int returnCode;
 
         private boolean doneFlag = false;
 
-        public void packageInstalled(String packageName, int returnCode) {
+        public void packageInstalled(String packageName, Bundle extras, int returnCode) {
             synchronized (this) {
                 this.returnCode = returnCode;
                 doneFlag = true;
@@ -203,7 +205,7 @@
 
     public void invokeInstallPackage(Uri packageURI, int flags, GenericReceiver receiver,
             boolean shouldSucceed) {
-        PackageInstallObserver observer = new PackageInstallObserver();
+        TestInstallObserver observer = new TestInstallObserver();
         mContext.registerReceiver(receiver, receiver.filter);
         try {
             // Wait on observer
@@ -261,7 +263,7 @@
     }
 
     public void invokeInstallPackageFail(Uri packageURI, int flags, int expectedResult) {
-        PackageInstallObserver observer = new PackageInstallObserver();
+        TestInstallObserver observer = new TestInstallObserver();
         try {
             // Wait on observer
             synchronized (observer) {
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index 6d29c69..92ecd24 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -61,7 +61,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on March 3, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on April 1, 2014.
 <br/>Any versions with less than 0.1% distribution are not shown.</em>
 </p>
 
@@ -92,7 +92,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on March 3, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on April 1, 2014.
 <br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
 
 
@@ -133,17 +133,17 @@
 </tr>
 <tr>
 <td>2.0</th>
-<td>91.1%</td>
+<td>89.4%</td>
 </tr>
 <tr>
 <td>3.0</th>
-<td>8.8%</td>
+<td>10.5%</td>
 </tr>
 </table>
 
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on March 3, 2014</em></p>
+<p style="clear:both"><em>Data collected during a 7-day period ending on April 1, 2014</em></p>
 
 
 
@@ -161,17 +161,17 @@
 var VERSION_DATA =
 [
   {
-    "chart": "//chart.googleapis.com/chart?chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat&chd=t%3A1.2%2C19.0%2C0.1%2C15.2%2C62.0%2C2.5&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&chs=500x250&cht=p",
+    "chart": "//chart.googleapis.com/chart?cht=p&chs=500x250&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A1.1%2C17.8%2C0.1%2C14.3%2C61.4%2C5.3&chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat",
     "data": [
       {
         "api": 8,
         "name": "Froyo",
-        "perc": "1.2"
+        "perc": "1.1"
       },
       {
         "api": 10,
         "name": "Gingerbread",
-        "perc": "19.0"
+        "perc": "17.8"
       },
       {
         "api": 13,
@@ -181,27 +181,27 @@
       {
         "api": 15,
         "name": "Ice Cream Sandwich",
-        "perc": "15.2"
+        "perc": "14.3"
       },
       {
         "api": 16,
         "name": "Jelly Bean",
-        "perc": "35.3"
+        "perc": "34.4"
       },
       {
         "api": 17,
         "name": "Jelly Bean",
-        "perc": "17.1"
+        "perc": "18.1"
       },
       {
         "api": 18,
         "name": "Jelly Bean",
-        "perc": "9.6"
+        "perc": "8.9"
       },
       {
         "api": 19,
         "name": "KitKat",
-        "perc": "2.5"
+        "perc": "5.3"
       }
     ]
   }
@@ -218,16 +218,15 @@
       "Large": {
         "hdpi": "0.6",
         "ldpi": "0.7",
-        "mdpi": "4.3",
+        "mdpi": "4.4",
         "tvdpi": "1.5",
         "xhdpi": "0.6"
       },
       "Normal": {
         "hdpi": "33.7",
-        "ldpi": "0.2",
-        "mdpi": "13.6",
-        "xhdpi": "19.9",
-        "xxhdpi": "11.9"
+        "mdpi": "13.2",
+        "xhdpi": "19.8",
+        "xxhdpi": "12.5"
       },
       "Small": {
         "ldpi": "8.1"
@@ -235,12 +234,12 @@
       "Xlarge": {
         "hdpi": "0.3",
         "ldpi": "0.1",
-        "mdpi": "4.3",
-        "xhdpi": "0.2"
+        "mdpi": "4.2",
+        "xhdpi": "0.3"
       }
     },
-    "densitychart": "//chart.googleapis.com/chart?chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chd=t%3A9.1%2C22.2%2C1.5%2C34.6%2C20.7%2C11.9&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&chs=400x250&cht=p",
-    "layoutchart": "//chart.googleapis.com/chart?chl=Xlarge%7CLarge%7CNormal%7CSmall&chd=t%3A4.9%2C7.7%2C79.3%2C8.1&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&chs=400x250&cht=p"
+    "densitychart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A8.9%2C21.8%2C1.5%2C34.6%2C20.7%2C12.6&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi",
+    "layoutchart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A4.9%2C7.8%2C79.3%2C8.1&chl=Xlarge%7CLarge%7CNormal%7CSmall"
   }
 ];
 
diff --git a/docs/html/design/index.jd b/docs/html/design/index.jd
index c687f33..7c7c5d9 100644
--- a/docs/html/design/index.jd
+++ b/docs/html/design/index.jd
@@ -1,5 +1,5 @@
 page.title=Design
-page.viewport-width=970
+page.viewport_width=970
 header.hide=1
 footer.hide=1
 @jd:body
diff --git a/docs/html/develop/index.jd b/docs/html/develop/index.jd
index 083b428..eb28da8 100644
--- a/docs/html/develop/index.jd
+++ b/docs/html/develop/index.jd
@@ -1,6 +1,6 @@
 fullpage=true
 page.title=Develop
-page.viewport-width=970
+page.viewport_width=970
 header.hide=1
 carousel=1
 tabbedList=1
diff --git a/docs/html/distribute/index.jd b/docs/html/distribute/index.jd
index d2534b9..6c6e113 100644
--- a/docs/html/distribute/index.jd
+++ b/docs/html/distribute/index.jd
@@ -1,5 +1,5 @@
 page.title=Distribute Apps
-page.viewport-width=970
+page.viewport_width=970
 header.hide=1
 
 @jd:body
diff --git a/docs/html/google/index.jd b/docs/html/google/index.jd
index b743b66..2e97d62 100644
--- a/docs/html/google/index.jd
+++ b/docs/html/google/index.jd
@@ -125,7 +125,7 @@
 <img src="{@docRoot}images/google/analytics.png" width="40" />
   </div>
     <h4><a class="external-link" 
-href="https://developers.google.com/analytics/devguides/collection/android/v2/"
+href="https://developers.google.com/analytics/devguides/collection/android/v4/"
   >Google Analytics</a></h4>
 
 <p>Measure your success and gain insights into how users engage with your app content
diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
index 506cf9d..826dcff 100644
--- a/docs/html/guide/components/intents-common.jd
+++ b/docs/html/guide/components/intents-common.jd
@@ -11,6 +11,18 @@
         <span class="less" style="display:none">show less</span></a></h2>
 
 <ol id="tocIntents" class="hide-nested">
+  <li><a href="#Clock">Alarm Clock</a>
+    <ol>
+      <li><a href="#CreateAlarm">Create an alarm</a></li>
+      <li><a href="#CreateTimer">Create a timer</a></li>
+      <li><a href="#ShowAlarms">Show all alarms</a></li>
+    </ol>
+  </li>
+  <li><a href="#Calendar">Calendar</a>
+    <ol>
+      <li><a href="#AddEvent">Add a calendar event</a></li>
+    </ol>
+  </li>
   <li><a href="#Camera">Camera</a>
     <ol>
       <li><a href="#ImageCapture">Capture a picture or video and return it</a></li>
@@ -116,6 +128,292 @@
 
 
 
+
+
+
+
+<h2 id="Clock">Alarm Clock</h2>
+
+
+<h3 id="CreateAlarm">Create an alarm</h3>
+
+<p>To create a new alarm, use the {@link android.provider.AlarmClock#ACTION_SET_ALARM}
+action and specify alarm details such as the time and message using extras defined below.</p>
+
+<p class="note"><strong>Note:</strong> Only the hour, minutes, and message extras are available
+since Android 2.3 (API level 9). The other extras were added in later versions of the platform.</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.provider.AlarmClock#ACTION_SET_ALARM}</dd>
+
+<dt><b>Data URI</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>None
+</dd>
+
+<dt><b>Extras</b></dt>
+<dd>
+  <dl>
+    <dt>{@link android.provider.AlarmClock#EXTRA_HOUR}</dt>
+      <dd>The hour for the alarm.</dd>
+    <dt>{@link android.provider.AlarmClock#EXTRA_MINUTES}</dt>
+      <dd>The minutes for the alarm.</dd>
+    <dt>{@link android.provider.AlarmClock#EXTRA_MESSAGE}</dt>
+      <dd>A custom message to identify the alarm.</dd>
+    <dt>{@link android.provider.AlarmClock#EXTRA_DAYS}</dt>
+      <dd>An {@link java.util.ArrayList} including each week day on which this alarm should
+      be repeated. Each day must be declared with an integer from the {@link java.util.Calendar}
+      class such as {@link java.util.Calendar#MONDAY}.
+      <p>For a one-time alarm, do not specify this extra.</dd>
+    <dt>{@link android.provider.AlarmClock#EXTRA_RINGTONE}</dt>
+      <dd>A {@code content:} URI specifying a ringtone to use with the alarm, or {@link
+      android.provider.AlarmClock#VALUE_RINGTONE_SILENT} for no ringtone.
+      <p>To use the default ringtone, do not specify this extra.</dd>
+    <dt>{@link android.provider.AlarmClock#EXTRA_VIBRATE}</dt>
+      <dd>A boolean specifying whether to vibrate for this alarm.</dd>
+    <dt>{@link android.provider.AlarmClock#EXTRA_SKIP_UI}</dt>
+      <dd>A boolean specifying whether the responding app should skip its UI when setting the alarm.
+      If true, the app should bypass any confirmation UI and simply set the specified alarm.</dd>
+  </dl>
+</dd>
+
+
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+public void createAlarm(String message, int hour, int minutes) {
+    Intent intent = new Intent(AlarmClock.ACTION_SET_ALARM)
+            .putExtra(AlarmClock.EXTRA_MESSAGE, message)
+            .putExtra(AlarmClock.EXTRA_HOUR, hour)
+            .putExtra(AlarmClock.EXTRA_MINUTES, minutes);
+    if (intent.resolveActivity(getPackageManager()) != null) {
+        startActivity(intent);
+    }
+}
+</pre>
+
+<div class="note"><strong>Note:</strong>
+<p>In order to invoke the {@link
+android.provider.AlarmClock#ACTION_SET_ALARM} intent, your app must have the
+{@link android.Manifest.permission#SET_ALARM} permission:</p>
+<pre>
+&lt;uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
+</pre>
+</div>
+
+
+<p><b>Example intent filter:</b></p>
+<pre>
+&lt;activity ...>
+    &lt;intent-filter>
+        &lt;action android:name="android.intent.action.SET_ALARM" />
+        &lt;category android:name="android.intent.category.DEFAULT" />
+    &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+
+
+<h3 id="CreateTimer">Create a timer</h3>
+
+<p>To create a countdown timer, use the {@link android.provider.AlarmClock#ACTION_SET_TIMER}
+action and specify timer details such as the duration using extras defined below.</p>
+
+<p class="note"><strong>Note:</strong> This intent was added
+in Android 4.4 (API level 19).</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.provider.AlarmClock#ACTION_SET_TIMER}</dd>
+
+<dt><b>Data URI</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>None
+</dd>
+
+<dt><b>Extras</b></dt>
+<dd>
+  <dl>
+    <dt>{@link android.provider.AlarmClock#EXTRA_LENGTH}</dt>
+      <dd>The length of the timer in seconds.</dd>
+    <dt>{@link android.provider.AlarmClock#EXTRA_MESSAGE}</dt>
+      <dd>A custom message to identify the timer.</dd>
+    <dt>{@link android.provider.AlarmClock#EXTRA_SKIP_UI}</dt>
+      <dd>A boolean specifying whether the responding app should skip its UI when setting the timer.
+      If true, the app should bypass any confirmation UI and simply start the specified timer.</dd>
+  </dl>
+</dd>
+
+
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+public void startTimer(String message, int seconds) {
+    Intent intent = new Intent(AlarmClock.ACTION_SET_TIMER)
+            .putExtra(AlarmClock.EXTRA_MESSAGE, message)
+            .putExtra(AlarmClock.EXTRA_LENGTH, seconds)
+            .putExtra(AlarmClock.EXTRA_SKIP_UI, true);
+    if (intent.resolveActivity(getPackageManager()) != null) {
+        startActivity(intent);
+    }
+}
+</pre>
+
+<div class="note"><strong>Note:</strong>
+<p>In order to invoke the {@link
+android.provider.AlarmClock#ACTION_SET_TIMER} intent, your app must have the
+{@link android.Manifest.permission#SET_ALARM} permission:</p>
+<pre>
+&lt;uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
+</pre>
+</div>
+
+
+<p><b>Example intent filter:</b></p>
+<pre>
+&lt;activity ...>
+    &lt;intent-filter>
+        &lt;action android:name="android.intent.action.SET_TIMER" />
+        &lt;category android:name="android.intent.category.DEFAULT" />
+    &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+
+
+
+
+<h3 id="ShowAlarms">Show all alarms</h3>
+
+<p>To show the list of alarms, use the {@link android.provider.AlarmClock#ACTION_SHOW_ALARMS}
+action.</p>
+
+<p>Although not many apps will invoke this intent (it's primarily used by system apps),
+any app that behaves as an alarm clock should implement
+this intent filter and respond by showing the list of current alarms.</p>
+
+<p class="note"><strong>Note:</strong> This intent was added
+in Android 4.4 (API level 19).</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.provider.AlarmClock#ACTION_SHOW_ALARMS}</dd>
+
+<dt><b>Data URI</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>None
+</dd>
+</dl>
+
+<p><b>Example intent filter:</b></p>
+<pre>
+&lt;activity ...>
+    &lt;intent-filter>
+        &lt;action android:name="android.intent.action.SHOW_ALARMS" />
+        &lt;category android:name="android.intent.category.DEFAULT" />
+    &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+
+
+
+
+
+<h2 id="Calendar">Calendar</h2>
+
+
+<h3 id="AddEvent">Add a calendar event</h3>
+
+<p>To add a new event to the user's calendar, use the {@link android.content.Intent#ACTION_INSERT}
+action and specify the data URI with {@link android.provider.CalendarContract.Events#CONTENT_URI
+Events.CONTENT_URI}. You can then specify various event details using extras defined below.</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.content.Intent#ACTION_INSERT}</dd>
+
+<dt><b>Data URI</b></dt>
+<dd>{@link android.provider.CalendarContract.Events#CONTENT_URI
+Events.CONTENT_URI}</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>{@code "vnd.android.cursor.dir/event"}
+</dd>
+
+<dt><b>Extras</b></dt>
+<dd>
+  <dl>
+    <dt>{@link android.provider.CalendarContract#EXTRA_EVENT_ALL_DAY}</dt>
+      <dd>A boolean specifying whether this is an all-day event.</dd>
+    <dt>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME}</dt>
+      <dd>The start time of the event (milliseconds since epoch).</dd>
+    <dt>{@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME}</dt>
+      <dd>The end time of the event (milliseconds since epoch).</dd>
+    <dt>{@link android.provider.CalendarContract.EventsColumns#TITLE}</dt>
+      <dd>The event title.</dd>
+    <dt>{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION}</dt>
+      <dd>The event description.</dd>
+    <dt>{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION}</dt>
+      <dd>The event location.</dd>
+    <dt>{@link android.content.Intent#EXTRA_EMAIL}</dt>
+      <dd>A comma-separated list of email addresses that specify the invitees.</dd>
+  </dl>
+  <p>Many more event details can be specified using the constants defined in the
+  {@link android.provider.CalendarContract.EventsColumns} class.</p>
+</dd>
+
+
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+public void addEvent(String title, String location, Calendar begin, Calendar end) {
+    Intent intent = new Intent(Intent.ACTION_INSERT)
+            .setData(Events.CONTENT_URI)
+            .putExtra(Events.TITLE, title)
+            .putExtra(Events.EVENT_LOCATION, location)
+            .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, begin)
+            .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, end);
+    if (intent.resolveActivity(getPackageManager()) != null) {
+        startActivity(intent);
+    }
+}
+</pre>
+
+
+<p><b>Example intent filter:</b></p>
+<pre>
+&lt;activity ...>
+    &lt;intent-filter>
+        &lt;action android:name="android.intent.action.INSERT" />
+        &lt;data android:mimeType="vnd.android.cursor.dir/event" />
+        &lt;category android:name="android.intent.category.DEFAULT" />
+    &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+
+
+
+
+
+
+
+
+
+
+
+
 <h2 id="Camera">Camera</h2>
 
 
@@ -211,6 +509,7 @@
 
 
 
+
 <h2 id="Contacts">Contacts/People App</h2>
 
 
@@ -427,7 +726,7 @@
 <dd>The type is inferred from contact URI.
 </dd>
 
-<dt><b>Extras</b> (optional)</dt>
+<dt><b>Extras</b></dt>
 <dd>One or more of the extras defined in {@link android.provider.ContactsContract.Intents.Insert}
 so you can populate fields of the contact details.
 </dd>
@@ -469,7 +768,7 @@
 <dt><b>MIME Type</b></dt>
 <dd>{@link android.provider.ContactsContract.Contacts#CONTENT_TYPE Contacts.CONTENT_TYPE}</dd>
 
-<dt><b>Extras</b> (optional)</dt>
+<dt><b>Extras</b></dt>
 <dd>One or more of the extras defined in {@link android.provider.ContactsContract.Intents.Insert}.
 </dd>
 </dl>
@@ -523,7 +822,7 @@
   </dl>
 </dd>
 
-<dt><b>Extras</b> (optional)</dt>
+<dt><b>Extras</b></dt>
 <dd>
   <dl>
     <dt>{@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL}</dt>
@@ -648,7 +947,7 @@
 <dd>The MIME type corresponding to the file type the user should select.
 </dd>
 
-<dt><b>Extras</b> (optional)</dt>
+<dt><b>Extras</b></dt>
 <dd>
   <dl>
     <dt>{@link android.content.Intent#EXTRA_ALLOW_MULTIPLE}
@@ -768,7 +1067,7 @@
 <dd>The MIME type corresponding to the file type the user should select.
 </dd>
 
-<dt><b>Extras</b> (optional)</dt>
+<dt><b>Extras</b></dt>
 <dd>
   <dl>
     <dt>{@link android.content.Intent#EXTRA_MIME_TYPES}
@@ -1139,7 +1438,7 @@
   </dl>
 </dd>
 
-<dt><b>Extras</b> (optional)</dt>
+<dt><b>Extras</b></dt>
 <dd>
   <dl>
     <dt><code>"subject"</code></dt>
diff --git a/docs/html/index.jd b/docs/html/index.jd
index d645246..99a469a 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -1,5 +1,5 @@
 fullpage=true
-page.viewport-width=970
+page.viewport_width=970
 no_footer_links=true
 carousel=true
 excludeFromSuggestions=true
diff --git a/docs/html/sdk/installing/studio-build.jd b/docs/html/sdk/installing/studio-build.jd
index 41ad5de..8674134 100644
--- a/docs/html/sdk/installing/studio-build.jd
+++ b/docs/html/sdk/installing/studio-build.jd
@@ -1,4 +1,4 @@
-page.title=Building your Project
+page.title=Building Your Project with Gradle
 
 @jd:body
 
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index 0e543e4..c281644 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -37,7 +37,7 @@
           <li><a href="<?cs var:toroot ?>sdk/installing/studio-layout.html">
               Using the Layout Editor</a></li>
           <li><a href="<?cs var:toroot ?>sdk/installing/studio-build.html">
-              Building your Project</a></li>
+              Building Your Project with Gradle</a></li>
           </ul>
       </li>
       <li><a href="<?cs var:toroot ?>sdk/exploring.html">
diff --git a/docs/html/training/basics/firstapp/creating-project.jd b/docs/html/training/basics/firstapp/creating-project.jd
index 50485db..c4cb362 100644
--- a/docs/html/training/basics/firstapp/creating-project.jd
+++ b/docs/html/training/basics/firstapp/creating-project.jd
@@ -10,9 +10,9 @@
 
 
 <!-- This is the training bar -->
-<div id="tb-wrapper"> 
-<div id="tb"> 
- 
+<div id="tb-wrapper">
+<div id="tb">
+
 <h2>This lesson teaches you to</h2>
 
 <ol>
@@ -27,10 +27,10 @@
 SDK</a></li>
   <li><a href="{@docRoot}tools/projects/index.html">Managing Projects</a></li>
 </ul>
- 
- 
-</div> 
-</div> 
+
+
+</div>
+</div>
 
 <p>An Android project contains all the files that comprise the source code for your Android
 app. The Android SDK tools make it easy to start a new Android project with a set of
@@ -42,7 +42,7 @@
 
 <p class="note"><strong>Note:</strong> You should already have the Android SDK installed, and if
 you're using Eclipse, you should also have the <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT
-plugin</a> installed (version 21.0.0 or higher). If you don't have these, follow the guide to <a
+plugin</a> installed (version 22.6.2 or higher). If you don't have these, follow the guide to <a
 href="{@docRoot}sdk/installing/index.html">Installing the Android SDK</a> before you start this
 lesson.</p>
 
@@ -50,7 +50,7 @@
 <h2 id="Eclipse">Create a Project with Eclipse</h2>
 
 <ol>
-  <li>Click <strong>New</strong> <img src="{@docRoot}images/tools/eclipse-new.png" 
+  <li>Click <strong>New</strong> <img src="{@docRoot}images/tools/eclipse-new.png"
   style="vertical-align:baseline;margin:0" /> in the toolbar.</li>
   <li>In the window that appears, open the <strong>Android</strong> folder,
   select <strong>Android Application Project</strong>, and click <strong>Next</strong>.</li>
@@ -116,11 +116,11 @@
   <li>Now you can select an activity template from which to begin building your app.
     <p>For this project, select <strong>BlankActivity</strong> and click <strong>Next</strong>.</p>
   </li>
-  <li>Leave all the details for the activity in their default state and click 
+  <li>Leave all the details for the activity in their default state and click
     <strong>Finish</strong>.</li>
 </ol>
 
-<p>Your Android project is now a basic "Hello World" app that contains some default files. 
+<p>Your Android project is now a basic "Hello World" app that contains some default files.
 To run the app, continue to the <a href="running-app.html">next lesson</a>.</p>
 
 
@@ -155,7 +155,7 @@
 projects.</p></li>
 </ol>
 
-<p>Your Android project is now a basic "Hello World" app that contains some default files. 
+<p>Your Android project is now a basic "Hello World" app that contains some default files.
 To run the app, continue to the <a href="running-app.html">next lesson</a>.</p>
 
 <p class="note"><strong>Tip:</strong> Add the <code>platform-tools/</code> as well as the
diff --git a/docs/html/training/basics/firstapp/index.jd b/docs/html/training/basics/firstapp/index.jd
index 4c1a0dc3..1b49096 100644
--- a/docs/html/training/basics/firstapp/index.jd
+++ b/docs/html/training/basics/firstapp/index.jd
@@ -8,21 +8,21 @@
 
 @jd:body
 
-<div id="tb-wrapper"> 
-<div id="tb"> 
- 
-<h2>Dependencies and prerequisites</h2> 
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2>
 
 <ul>
   <li><a href="http://developer.android.com/sdk/index.html">Android SDK</a></li>
-  <li><a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> 20.0.0 or higher
+  <li><a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> 22.6.2 or higher
     (if you're using Eclipse)</li>
 </ul>
- 
-</div> 
-</div> 
- 
-<p>Welcome to Android application development!</p> 
+
+</div>
+</div>
+
+<p>Welcome to Android application development!</p>
 
 <p>This class teaches you how to build your first Android app. You’ll learn how to create an Android
 project and run a debuggable version of the app. You'll also learn some fundamentals of Android app
@@ -36,6 +36,10 @@
   <li>Download the latest SDK tools and platforms using the SDK Manager.</li>
 </ol>
 
+<p class="note"><strong>Note:</strong> Make sure you install the most recent versions of the ADT
+plugin and the Android SDK before you start this class. The procedures described in this class may
+not apply to earlier versions.</p>
+
 <p>If you haven't already done these tasks, start by downloading the
   <a href="{@docRoot}sdk/index.html">Android SDK</a> and following the install steps.
   Once you've finished the setup, you're ready to begin this class.</p>
diff --git a/docs/html/training/basics/firstapp/starting-activity.jd b/docs/html/training/basics/firstapp/starting-activity.jd
index 9aa25a3..27d2c10 100644
--- a/docs/html/training/basics/firstapp/starting-activity.jd
+++ b/docs/html/training/basics/firstapp/starting-activity.jd
@@ -10,9 +10,9 @@
 
 
 <!-- This is the training bar -->
-<div id="tb-wrapper"> 
-<div id="tb"> 
- 
+<div id="tb-wrapper">
+<div id="tb">
+
 <h2>This lesson teaches you to</h2>
 
 <ol>
@@ -30,10 +30,10 @@
   <li><a href="{@docRoot}sdk/installing/index.html">Installing the
 SDK</a></li>
 </ul>
- 
- 
-</div> 
-</div> 
+
+
+</div>
+</div>
 
 
 
@@ -151,7 +151,7 @@
 </pre>
 
 <p class="note"><strong>Note:</strong>
-You now need an import statement for <code>android.widget.EditText</code>. 
+You now need an import statement for <code>android.widget.EditText</code>.
 You'll define the <code>EXTRA_MESSAGE</code> constant in a moment.</p>
 
 <p>An {@link android.content.Intent} can carry a collection of various data types as key-value
@@ -212,7 +212,7 @@
 <p>To create a new activity using Eclipse:</p>
 
 <ol>
-  <li>Click <strong>New</strong> <img src="{@docRoot}images/tools/eclipse-new.png" 
+  <li>Click <strong>New</strong> <img src="{@docRoot}images/tools/eclipse-new.png"
   style="vertical-align:baseline;margin:0" /> in the toolbar.</li>
   <li>In the window that appears, open the <strong>Android</strong> folder
   and select <strong>Android Activity</strong>. Click <strong>Next</strong>.</li>
@@ -247,15 +247,19 @@
   <li>There's also an implementation of {@link android.app.Activity#onOptionsItemSelected
   onOptionsItemSelected()} which handles the behavior for the action bar's <em>Up</em> behavior.
   Keep this one the way it is.</li>
-  <li>There's also a <code>PlaceholderFragment</code> class that extends 
+  <li>There's also a <code>PlaceholderFragment</code> class that extends
 {@link android.app.Fragment}. You will not need this class in the final version of this
 activity.</li>
 </ul>
 
-<p>Fragments decompose application functionality and UI into reusable modules. For more 
-information on fragments, see the <a href="{@docRoot}guide/components/fragments.html">Fragments 
+<p>Fragments decompose application functionality and UI into reusable modules. For more
+information on fragments, see the <a href="{@docRoot}guide/components/fragments.html">Fragments
 API Guide</a>. The final version of this activity does not use fragments.</p>
 
+<p class="note"><strong>Note:</strong> Your activity may look different if you did not use
+the latest version of the ADT plugin. Make sure you install the latest version of the
+<a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT plugin</a> to complete this tutorial.</p>
+
 <p>The {@code DisplayMessageActivity} class should now look like this:</p>
 
 <pre>
diff --git a/docs/html/wear/images/laptop-bridge.png b/docs/html/wear/images/laptop-bridge.png
index b481224..083b82b 100644
--- a/docs/html/wear/images/laptop-bridge.png
+++ b/docs/html/wear/images/laptop-bridge.png
Binary files differ
diff --git a/docs/html/wear/index.jd b/docs/html/wear/index.jd
index b977554..a6a6460 100644
--- a/docs/html/wear/index.jd
+++ b/docs/html/wear/index.jd
@@ -1,5 +1,5 @@
 page.title=Android Wear
-page.viewport-width=970
+page.viewport_width=970
 fullpage=true
 no_footer_links=true
 page.customHeadTag=<link rel="stylesheet" type="text/css" href="/wear/css/wear.css">
diff --git a/docs/html/wear/notifications/creating.jd b/docs/html/wear/notifications/creating.jd
index 133d057..ce9e117 100644
--- a/docs/html/wear/notifications/creating.jd
+++ b/docs/html/wear/notifications/creating.jd
@@ -37,7 +37,7 @@
 <h2 id="Import">Import the Necessary Classes</h2>
 
 <p>To begin development, you must first complete the instructions in the <a
-href="{@docRoot}wear/preview/start">Get Started with the Developer Preview</a> document.
+href="{@docRoot}wear/preview/start.html">Get Started with the Developer Preview</a> document.
 As mentioned in that document, your app must include
 both the <a href="http://developer.android.com/tools/support-library/features.html#v4">v4 support
 library</a> and the Developer Preview support library. So to get started,
@@ -252,7 +252,7 @@
 will not work.</p>
 
 <p>To continue enhancing your notifications for wearables using
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder"
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"
   ><code>WearableNotifications.Builder</code></a> and other APIs in the
   preview support library, see the following developer guides:</p>
 
diff --git a/docs/html/wear/notifications/remote-input.jd b/docs/html/wear/notifications/remote-input.jd
index a3d45df..1668363 100644
--- a/docs/html/wear/notifications/remote-input.jd
+++ b/docs/html/wear/notifications/remote-input.jd
@@ -119,7 +119,7 @@
 // Create wearable notification and add remote input
 Notification replyNotification =
         new WearableNotifications.Builder(replyNotificationBuilder)
-        .addRemoteInputForContentIntent(replyAction)
+        .addRemoteInputForContentIntent(remoteInput)
         .build();
 </pre>
 
@@ -138,7 +138,7 @@
 <p>If the "Reply" action is not your notification's primary action and you want to enable
 voice input for a secondary action, add the
   <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to a new action button defined by an
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/Action.html">
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">
 <code>Action</code></a> object.</p>
 
 <p>You should instantiate the
diff --git a/graphics/java/android/graphics/TemporaryBuffer.java b/graphics/java/android/graphics/TemporaryBuffer.java
index c5b8143..36a2275 100644
--- a/graphics/java/android/graphics/TemporaryBuffer.java
+++ b/graphics/java/android/graphics/TemporaryBuffer.java
@@ -31,7 +31,7 @@
         }
 
         if (buf == null || buf.length < len) {
-            buf = new char[ArrayUtils.idealCharArraySize(len)];
+            buf = ArrayUtils.newUnpaddedCharArray(len);
         }
 
         return buf;
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 3c3c841..52352c4 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -80,8 +80,8 @@
     }
 
     /**
-     * Create a new layer drawable with the specified list of layers and the specified
-     * constant state.
+     * Create a new layer drawable with the specified list of layers and the
+     * specified constant state.
      *
      * @param layers The list of layers to add to this drawable.
      * @param state The constant drawable state.
@@ -326,6 +326,7 @@
         childDrawable.mInsetR = right;
         childDrawable.mInsetB = bottom;
         st.mNum++;
+        st.invalidateCache();
 
         layer.setCallback(this);
     }
@@ -419,6 +420,7 @@
                 }
 
                 childDrawable.mDrawable = drawable;
+                mLayerState.invalidateCache();
                 return true;
             }
         }
@@ -527,6 +529,25 @@
         }
     }
 
+    private void computeStackedPadding(Rect padding) {
+        padding.left = 0;
+        padding.top = 0;
+        padding.right = 0;
+        padding.bottom = 0;
+
+        // Take the max padding.
+        final ChildDrawable[] array = mLayerState.mChildren;
+        final int N = mLayerState.mNum;
+        for (int i = 0; i < N; i++) {
+            refreshChildPadding(i, array[i]);
+
+            padding.left = Math.max(padding.left, mPaddingL[i]);
+            padding.top = Math.max(padding.top, mPaddingT[i]);
+            padding.right = Math.max(padding.right, mPaddingR[i]);
+            padding.bottom = Math.max(padding.bottom, mPaddingB[i]);
+        }
+    }
+
     /**
      * @hide
      */
@@ -579,25 +600,6 @@
         }
     }
 
-    private void computeStackedPadding(Rect padding) {
-        padding.left = 0;
-        padding.top = 0;
-        padding.right = 0;
-        padding.bottom = 0;
-
-        // Take the max padding.
-        final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
-        for (int i = 0; i < N; i++) {
-            refreshChildPadding(i, array[i]);
-
-            padding.left = Math.max(padding.left, mPaddingL[i]);
-            padding.top = Math.max(padding.top, mPaddingT[i]);
-            padding.right = Math.max(padding.right, mPaddingR[i]);
-            padding.bottom = Math.max(padding.bottom, mPaddingB[i]);
-        }
-    }
-
     @Override
     public boolean setVisible(boolean visible, boolean restart) {
         final boolean changed = super.setVisible(visible, restart);
@@ -632,7 +634,8 @@
     public int getAlpha() {
         final ChildDrawable[] array = mLayerState.mChildren;
         if (mLayerState.mNum > 0) {
-            // All layers should have the same alpha set on them - just return the first one
+            // All layers should have the same alpha set on them - just return
+            // the first one
             return array[0].mDrawable.getAlpha();
         } else {
             return super.getAlpha();
@@ -649,12 +652,11 @@
     }
 
     /**
-     * Sets the opacity of this drawable directly, instead of collecting the states from
-     * the layers
+     * Sets the opacity of this drawable directly, instead of collecting the
+     * states from the layers
      *
-     * @param opacity The opacity to use, or {@link PixelFormat#UNKNOWN PixelFormat.UNKNOWN}
-     * for the default behavior
-     *
+     * @param opacity The opacity to use, or {@link PixelFormat#UNKNOWN
+     *            PixelFormat.UNKNOWN} for the default behavior
      * @see PixelFormat#UNKNOWN
      * @see PixelFormat#TRANSLUCENT
      * @see PixelFormat#TRANSPARENT
@@ -702,7 +704,7 @@
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
             final ChildDrawable r = array[i];
-            if (r.mDrawable.setState(state)) {
+            if (r.mDrawable.isStateful() && r.mDrawable.setState(state)) {
                 changed = true;
             }
 
@@ -890,7 +892,7 @@
         public int[] mThemeAttrs;
         public int mInsetL, mInsetT, mInsetR, mInsetB;
         public int mId;
-        
+
         ChildDrawable() {
             // Default empty constructor.
         }
@@ -920,14 +922,11 @@
         int mChangingConfigurations;
         int mChildrenChangingConfigurations;
 
-        private boolean mHaveOpacity = false;
+        private boolean mHaveOpacity;
         private int mOpacity;
 
-        private boolean mHaveStateful = false;
-        private boolean mStateful;
-
-        private boolean mCheckedConstantState;
-        private boolean mCanConstantState;
+        private boolean mHaveIsStateful;
+        private boolean mIsStateful;
 
         private boolean mAutoMirrored;
 
@@ -951,9 +950,8 @@
 
                 mHaveOpacity = orig.mHaveOpacity;
                 mOpacity = orig.mOpacity;
-                mHaveStateful = orig.mHaveStateful;
-                mStateful = orig.mStateful;
-                mCheckedConstantState = mCanConstantState = true;
+                mHaveIsStateful = orig.mHaveIsStateful;
+                mIsStateful = orig.mIsStateful;
                 mAutoMirrored = orig.mAutoMirrored;
                 mPaddingMode = orig.mPaddingMode;
                 mThemeAttrs = orig.mThemeAttrs;
@@ -993,49 +991,54 @@
                 return mOpacity;
             }
 
+            final ChildDrawable[] array = mChildren;
             final int N = mNum;
-            int op = N > 0 ? mChildren[0].mDrawable.getOpacity() : PixelFormat.TRANSPARENT;
+            int op = N > 0 ? array[0].mDrawable.getOpacity() : PixelFormat.TRANSPARENT;
             for (int i = 1; i < N; i++) {
-                op = Drawable.resolveOpacity(op, mChildren[i].mDrawable.getOpacity());
+                op = Drawable.resolveOpacity(op, array[i].mDrawable.getOpacity());
             }
+
             mOpacity = op;
             mHaveOpacity = true;
             return op;
         }
 
         public final boolean isStateful() {
-            if (mHaveStateful) {
-                return mStateful;
+            if (mHaveIsStateful) {
+                return mIsStateful;
             }
 
-            boolean stateful = false;
+            final ChildDrawable[] array = mChildren;
             final int N = mNum;
+            boolean isStateful = false;
             for (int i = 0; i < N; i++) {
-                if (mChildren[i].mDrawable.isStateful()) {
-                    stateful = true;
+                if (array[i].mDrawable.isStateful()) {
+                    isStateful = true;
                     break;
                 }
             }
 
-            mStateful = stateful;
-            mHaveStateful = true;
-            return stateful;
+            mIsStateful = isStateful;
+            mHaveIsStateful = true;
+            return isStateful;
         }
 
-        public boolean canConstantState() {
-            if (!mCheckedConstantState && mChildren != null) {
-                mCanConstantState = true;
-                final int N = mNum;
-                for (int i = 0; i < N; i++) {
-                    if (mChildren[i].mDrawable.getConstantState() == null) {
-                        mCanConstantState = false;
-                        break;
-                    }
+        public final boolean canConstantState() {
+            final ChildDrawable[] array = mChildren;
+            final int N = mNum;
+            for (int i = 0; i < N; i++) {
+                if (array[i].mDrawable.getConstantState() == null) {
+                    return false;
                 }
-                mCheckedConstantState = true;
             }
 
-            return mCanConstantState;
+            // Don't cache the result, this method is not called very often.
+            return true;
+        }
+
+        public void invalidateCache() {
+            mHaveOpacity = false;
+            mHaveIsStateful = false;
         }
     }
 }
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index b66d86d..64de95f 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -39,7 +39,6 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
-import java.util.ArrayList;
 
 /**
  * Documentation pending.
@@ -98,7 +97,7 @@
     protected boolean onStateChange(int[] stateSet) {
         super.onStateChange(stateSet);
 
-        if (mRipplePaint != null) {
+        if (mRipplePaint != null && mState.mTint != null) {
             final ColorStateList stateList = mState.mTint;
             final int newColor = stateList.getColorForState(stateSet, 0);
             final int oldColor = mRipplePaint.getColor();
@@ -122,7 +121,7 @@
 
     @Override
     public boolean isStateful() {
-        return super.isStateful() || mState.mTint.isStateful();
+        return super.isStateful() || mState.mTint != null && mState.mTint.isStateful();
     }
 
     @Override
@@ -150,10 +149,6 @@
 
         if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_tint] == 0) {
             mState.mTint = a.getColorStateList(R.styleable.TouchFeedbackDrawable_tint);
-
-            if (mState.mTint == null) {
-                throw new RuntimeException("<touch-feedback> tag requires a 'tint' attribute");
-            }
         }
 
         if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_tintMode] == 0) {
@@ -400,9 +395,11 @@
         if (mRipplePaint == null) {
             mRipplePaint = new Paint();
             mRipplePaint.setAntiAlias(true);
-            
-            final int color = mState.mTint.getColorForState(getState(), Color.TRANSPARENT);
-            mRipplePaint.setColor(color);
+
+            if (mState.mTint != null) {
+                final int color = mState.mTint.getColorForState(getState(), Color.TRANSPARENT);
+                mRipplePaint.setColor(color);
+            }
         }
         return mRipplePaint;
     }
diff --git a/include/private/hwui/DrawGlInfo.h b/include/private/hwui/DrawGlInfo.h
index fc810be..a357a01 100644
--- a/include/private/hwui/DrawGlInfo.h
+++ b/include/private/hwui/DrawGlInfo.h
@@ -55,7 +55,10 @@
         kModeDraw,
         // Indicates the the functor is called only to perform
         // processing and that no draw should be attempted
-        kModeProcess
+        kModeProcess,
+        // Same as kModeProcess, however there is no GL context because it was
+        // lost or destroyed
+        kModeProcessNoContext
     };
 
     /**
@@ -65,14 +68,6 @@
     enum Status {
         // The functor is done
         kStatusDone = 0x0,
-        // The functor is requesting a redraw (the clip rect
-        // used by the redraw is specified by DrawGlInfo.)
-        // The rest of the UI might redraw too.
-        kStatusDraw = 0x1,
-        // The functor needs to be invoked again but will
-        // not redraw. Only the functor is invoked again
-        // (unless another functor requests a redraw.)
-        kStatusInvoke = 0x2,
         // DisplayList actually issued GL drawing commands.
         // This is used to signal the HardwareRenderer that the
         // buffers should be flipped - otherwise, there were no
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 9e367fc..5fa8f1d 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1499,13 +1499,13 @@
     virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
             bool useQuickReject) {
         if (mDisplayList && mDisplayList->isRenderable() && !mSkipInOrderDraw) {
-            mDisplayList->defer(deferStruct, level + 1);
+            mDisplayList->deferNodeInParent(deferStruct, level + 1);
         }
     }
     virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
             bool useQuickReject) {
         if (mDisplayList && mDisplayList->isRenderable() && !mSkipInOrderDraw) {
-            mDisplayList->replay(replayStruct, level + 1);
+            mDisplayList->replayNodeInParent(replayStruct, level + 1);
         }
     }
 
@@ -1548,14 +1548,16 @@
 };
 
 /**
- * Not a canvas operation, used only by 3d / z ordering logic in DisplayList::iterate()
+ * Not a canvas operation, used only by 3d / z ordering logic in RenderNode::iterate()
  */
 class DrawShadowOp : public DrawOp {
 public:
-    DrawShadowOp(const mat4& transformXY, const mat4& transformZ, float alpha,
+    DrawShadowOp(const mat4& transformXY, const mat4& transformZ,
+            float casterAlpha, bool casterUnclipped,
             float fallbackWidth, float fallbackHeight,
             const SkPath* outline, const SkPath* revealClip)
-            : DrawOp(NULL), mTransformXY(transformXY), mTransformZ(transformZ), mAlpha(alpha),
+            : DrawOp(NULL), mTransformXY(transformXY), mTransformZ(transformZ),
+            mCasterAlpha(casterAlpha), mCasterUnclipped(casterUnclipped),
             mFallbackWidth(fallbackWidth), mFallbackHeight(fallbackHeight),
             mOutline(outline), mRevealClip(revealClip) {}
 
@@ -1572,7 +1574,8 @@
             Op(casterPerimeter, *mRevealClip, kIntersect_PathOp, &casterPerimeter);
         }
 
-        return renderer.drawShadow(mTransformXY, mTransformZ, mAlpha, &casterPerimeter);
+        return renderer.drawShadow(mTransformXY, mTransformZ,
+                mCasterAlpha, mCasterUnclipped, &casterPerimeter);
     }
 
     virtual void output(int level, uint32_t logFlags) const {
@@ -1584,7 +1587,8 @@
 private:
     const mat4 mTransformXY;
     const mat4 mTransformZ;
-    const float mAlpha;
+    const float mCasterAlpha;
+    const bool mCasterUnclipped;
     const float mFallbackWidth;
     const float mFallbackHeight;
 
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 4457c61..27409a2 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -209,7 +209,7 @@
             dirtyRect.right, dirtyRect.bottom, !isBlend());
 
     displayList->computeOrdering();
-    displayList->defer(deferredState, 0);
+    displayList->deferNodeTree(deferredState);
 
     deferredUpdateScheduled = false;
 }
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index d808735..e1f484d 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -409,15 +409,6 @@
         for (size_t i = 0; i < count; i++) {
             Functor* f = functors.itemAt(i);
             result |= (*f)(DrawGlInfo::kModeProcess, &info);
-
-            if (result & DrawGlInfo::kStatusDraw) {
-                Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
-                dirty.unionWith(localDirty);
-            }
-
-            if (result & DrawGlInfo::kStatusInvoke) {
-                mFunctors.add(f);
-            }
         }
         resume();
     }
@@ -461,19 +452,10 @@
     interrupt();
 
     // call functor immediately after GL state setup
-    status_t result = (*functor)(DrawGlInfo::kModeDraw, &info);
-
-    if (result != DrawGlInfo::kStatusDone) {
-        Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
-        dirty.unionWith(localDirty);
-
-        if (result & DrawGlInfo::kStatusInvoke) {
-            mFunctors.add(functor);
-        }
-    }
+    (*functor)(DrawGlInfo::kModeDraw, &info);
 
     resume();
-    return result | DrawGlInfo::kStatusDrew;
+    return DrawGlInfo::kStatusDrew;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1924,14 +1906,14 @@
         if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
             status = startFrame();
             ReplayStateStruct replayStruct(*this, dirty, replayFlags);
-            displayList->replay(replayStruct, 0);
+            displayList->replayNodeTree(replayStruct);
             return status | replayStruct.mDrawGlStatus;
         }
 
         bool avoidOverdraw = !mCaches.debugOverdraw && !mCountOverdraw; // shh, don't tell devs!
         DeferredDisplayList deferredList(*currentClipRect(), avoidOverdraw);
         DeferStateStruct deferStruct(deferredList, *this, replayFlags);
-        displayList->defer(deferStruct, 0);
+        displayList->deferNodeTree(deferStruct);
 
         flushLayers();
         status = startFrame();
@@ -3203,7 +3185,7 @@
 }
 
 status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& casterTransformZ,
-        float casterAlpha, const SkPath* casterPerimeter) {
+        float casterAlpha, bool casterUnclipped, const SkPath* casterPerimeter) {
     if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
 
     // TODO: use quickRejectWithScissor. For now, always force enable scissor.
@@ -3260,7 +3242,7 @@
     Rect casterBounds(casterPerimeter->getBounds());
     casterTransformXY.mapRect(casterBounds);
 
-    bool isCasterOpaque = (casterAlpha == 1.0f);
+    bool isCasterOpaque = (casterAlpha == 1.0f) && casterUnclipped;
     // draw caster's shadows
     if (mCaches.propertyAmbientShadowStrength > 0) {
         paint.setARGB(casterAlpha * mCaches.propertyAmbientShadowStrength, 0, 0, 0);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 054767e..2debd2e 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -210,7 +210,7 @@
     virtual status_t drawRects(const float* rects, int count, const SkPaint* paint);
 
     status_t drawShadow(const mat4& casterTransformXY, const mat4& casterTransformZ,
-            float casterAlpha, const SkPath* casterPerimeter);
+            float casterAlpha, bool casterUnclipped, const SkPath* casterPerimeter);
 
     virtual void resetShader();
     virtual void setupShader(SkiaShader* shader);
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 675b215..34d98a1 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -132,10 +132,9 @@
 #define PROPERTY_SAVECOUNT 0
 
 template <class T>
-void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler,
-        const int level) {
+void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) {
 #if DEBUG_DISPLAY_LIST
-    properties().debugOutputProperties(level);
+    properties().debugOutputProperties(handler.level() + 1);
 #endif
     if (properties().getLeft() != 0 || properties().getTop() != 0) {
         renderer.translate(properties().getLeft(), properties().getTop());
@@ -302,7 +301,6 @@
             child->computeOrderingImpl(childOp, projectionChildren, projectionTransform);
         }
     }
-
 }
 
 class DeferOperationHandler {
@@ -313,15 +311,25 @@
         operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds);
     }
     inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); }
+    inline void startMark(const char* name) {} // do nothing
+    inline void endMark() {}
+    inline int level() { return mLevel; }
+    inline int replayFlags() { return mDeferStruct.mReplayFlags; }
 
 private:
     DeferStateStruct& mDeferStruct;
     const int mLevel;
 };
 
-void RenderNode::defer(DeferStateStruct& deferStruct, const int level) {
+void RenderNode::deferNodeTree(DeferStateStruct& deferStruct) {
+    DeferOperationHandler handler(deferStruct, 0);
+    if (properties().getTranslationZ() > 0.0f) issueDrawShadowOperation(Matrix4::identity(), handler);
+    issueOperations<DeferOperationHandler>(deferStruct.mRenderer, handler);
+}
+
+void RenderNode::deferNodeInParent(DeferStateStruct& deferStruct, const int level) {
     DeferOperationHandler handler(deferStruct, level);
-    iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level);
+    issueOperations<DeferOperationHandler>(deferStruct.mRenderer, handler);
 }
 
 class ReplayOperationHandler {
@@ -335,21 +343,31 @@
         operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
     }
     inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); }
+    inline void startMark(const char* name) {
+        mReplayStruct.mRenderer.startMark(name);
+    }
+    inline void endMark() {
+        mReplayStruct.mRenderer.endMark();
+        DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(),
+                mReplayStruct.mDrawGlStatus);
+    }
+    inline int level() { return mLevel; }
+    inline int replayFlags() { return mReplayStruct.mReplayFlags; }
 
 private:
     ReplayStateStruct& mReplayStruct;
     const int mLevel;
 };
 
-void RenderNode::replay(ReplayStateStruct& replayStruct, const int level) {
+void RenderNode::replayNodeTree(ReplayStateStruct& replayStruct) {
+    ReplayOperationHandler handler(replayStruct, 0);
+    if (properties().getTranslationZ() > 0.0f) issueDrawShadowOperation(Matrix4::identity(), handler);
+    issueOperations<ReplayOperationHandler>(replayStruct.mRenderer, handler);
+}
+
+void RenderNode::replayNodeInParent(ReplayStateStruct& replayStruct, const int level) {
     ReplayOperationHandler handler(replayStruct, level);
-
-    replayStruct.mRenderer.startMark(mName.string());
-    iterate<ReplayOperationHandler>(replayStruct.mRenderer, handler, level);
-    replayStruct.mRenderer.endMark();
-
-    DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(),
-            replayStruct.mDrawGlStatus);
+    issueOperations<ReplayOperationHandler>(replayStruct.mRenderer, handler);
 }
 
 void RenderNode::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes) {
@@ -373,10 +391,42 @@
     std::stable_sort(zTranslatedNodes.begin(), zTranslatedNodes.end());
 }
 
+template <class T>
+void RenderNode::issueDrawShadowOperation(const Matrix4& transformFromParent, T& handler) {
+    if (properties().getAlpha() <= 0.0f) return;
+
+    mat4 shadowMatrixXY(transformFromParent);
+    applyViewPropertyTransforms(shadowMatrixXY);
+
+    // Z matrix needs actual 3d transformation, so mapped z values will be correct
+    mat4 shadowMatrixZ(transformFromParent);
+    applyViewPropertyTransforms(shadowMatrixZ, true);
+
+    const SkPath* outlinePath = properties().getOutline().getPath();
+    const RevealClip& revealClip = properties().getRevealClip();
+    const SkPath* revealClipPath = revealClip.hasConvexClip()
+            ?  revealClip.getPath() : NULL; // only pass the reveal clip's path if it's convex
+
+    /**
+     * The drawing area of the caster is always the same as the its perimeter (which
+     * the shadow system uses) *except* in the inverse clip case. Inform the shadow
+     * system that the caster's drawing area (as opposed to its perimeter) has been
+     * clipped, so that it knows the caster can't be opaque.
+     */
+    bool casterUnclipped = !revealClip.willClip() || revealClip.hasConvexClip();
+
+    DisplayListOp* shadowOp  = new (handler.allocator()) DrawShadowOp(
+            shadowMatrixXY, shadowMatrixZ,
+            properties().getAlpha(), casterUnclipped,
+            properties().getWidth(), properties().getHeight(),
+            outlinePath, revealClipPath);
+    handler(shadowOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
+}
+
 #define SHADOW_DELTA 0.1f
 
 template <class T>
-void RenderNode::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes,
+void RenderNode::issueOperationsOf3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes,
         ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler) {
     const int size = zTranslatedNodes.size();
     if (size == 0
@@ -386,12 +436,6 @@
         return;
     }
 
-    int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-    LinearAllocator& alloc = handler.allocator();
-    ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, properties().getWidth(), properties().getHeight(),
-            SkRegion::kIntersect_Op); // clip to 3d root bounds
-    handler(clipOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
-
     /**
      * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters
      * with very similar Z heights to draw together.
@@ -419,26 +463,7 @@
             // attempt to render the shadow if the caster about to be drawn is its caster,
             // OR if its caster's Z value is similar to the previous potential caster
             if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) {
-
-                if (caster->properties().getAlpha() > 0.0f) {
-                    mat4 shadowMatrixXY(casterOp->mTransformFromParent);
-                    caster->applyViewPropertyTransforms(shadowMatrixXY);
-
-                    // Z matrix needs actual 3d transformation, so mapped z values will be correct
-                    mat4 shadowMatrixZ(casterOp->mTransformFromParent);
-                    caster->applyViewPropertyTransforms(shadowMatrixZ, true);
-
-                    const SkPath* outlinePath = caster->properties().getOutline().getPath();
-                    const RevealClip& revealClip = caster->properties().getRevealClip();
-                    const SkPath* revealClipPath = revealClip.hasConvexClip()
-                            ?  revealClip.getPath() : NULL; // only pass the reveal clip's path if it's convex
-
-                    DisplayListOp* shadowOp  = new (alloc) DrawShadowOp(
-                            shadowMatrixXY, shadowMatrixZ, caster->properties().getAlpha(),
-                            caster->properties().getWidth(), caster->properties().getHeight(),
-                            outlinePath, revealClipPath);
-                    handler(shadowOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
-                }
+                caster->issueDrawShadowOperation(casterOp->mTransformFromParent, handler);
 
                 lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
                 shadowIndex++;
@@ -461,17 +486,10 @@
         renderer.restoreToCount(restoreTo);
         drawIndex++;
     }
-    handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, properties().getClipToBounds());
 }
 
 template <class T>
-void RenderNode::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) {
-    int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-    LinearAllocator& alloc = handler.allocator();
-    ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, properties().getWidth(), properties().getHeight(),
-            SkRegion::kReplace_Op); // clip to projection surface root bounds
-    handler(clipOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
-
+void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& handler) {
     for (size_t i = 0; i < mProjectedNodes.size(); i++) {
         DrawDisplayListOp* childOp = mProjectedNodes[i];
 
@@ -483,7 +501,6 @@
         childOp->mSkipInOrderDraw = true;
         renderer.restoreToCount(restoreTo);
     }
-    handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, properties().getClipToBounds());
 }
 
 /**
@@ -496,7 +513,8 @@
  * defer vs replay logic, per operation
  */
 template <class T>
-void RenderNode::iterate(OpenGLRenderer& renderer, T& handler, const int level) {
+void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
+    const int level = handler.level();
     if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging
         ALOGW("Error: %s is drawing after destruction", mName.string());
         CRASH();
@@ -506,6 +524,8 @@
         return;
     }
 
+    handler.startMark(mName.string());
+
 #if DEBUG_DISPLAY_LIST
     Rect* clipRect = renderer.getClipRect();
     DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f",
@@ -521,7 +541,7 @@
     DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
 
-    setViewProperties<T>(renderer, handler, level + 1);
+    setViewProperties<T>(renderer, handler);
 
     bool quickRejected = properties().getClipToBounds()
             && renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight());
@@ -530,7 +550,7 @@
         buildZSortedChildList(zTranslatedNodes);
 
         // for 3d root, draw children with negative z values
-        iterate3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
+        issueOperationsOf3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
 
         DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
         const int saveCountOffset = renderer.getSaveCount() - 1;
@@ -541,23 +561,24 @@
 #if DEBUG_DISPLAY_LIST
             op->output(level + 1);
 #endif
-
             logBuffer.writeCommand(level, op->name());
             handler(op, saveCountOffset, properties().getClipToBounds());
 
             if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
-                iterateProjectedChildren(renderer, handler, level);
+                issueOperationsOfProjectedChildren(renderer, handler);
             }
         }
 
         // for 3d root, draw children with positive z values
-        iterate3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
+        issueOperationsOf3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
     }
 
     DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
     handler(new (alloc) RestoreToCountOp(restoreTo),
             PROPERTY_SAVECOUNT, properties().getClipToBounds());
     renderer.setOverrideLayerAlpha(1.0f);
+
+    handler.endMark();
 }
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 291d03d..fb5336d 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -92,8 +92,12 @@
     ANDROID_API void setData(DisplayListData* newData);
 
     void computeOrdering();
-    void defer(DeferStateStruct& deferStruct, const int level);
-    void replay(ReplayStateStruct& replayStruct, const int level);
+
+    void deferNodeTree(DeferStateStruct& deferStruct);
+    void deferNodeInParent(DeferStateStruct& deferStruct, const int level);
+
+    void replayNodeTree(ReplayStateStruct& replayStruct);
+    void replayNodeInParent(ReplayStateStruct& replayStruct, const int level);
 
     ANDROID_API void output(uint32_t level = 1);
 
@@ -164,19 +168,26 @@
             const mat4* transformFromProjectionSurface);
 
     template <class T>
-    inline void setViewProperties(OpenGLRenderer& renderer, T& handler, const int level);
+    inline void setViewProperties(OpenGLRenderer& renderer, T& handler);
 
     void buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes);
 
+    template<class T>
+    inline void issueDrawShadowOperation(const Matrix4& transformFromParent, T& handler);
+
     template <class T>
-    inline void iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes,
+    inline void issueOperationsOf3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes,
             ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler);
 
     template <class T>
-    inline void iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level);
+    inline void issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& handler);
 
+    /**
+     * Issue the RenderNode's operations into a handler, recursing for subtrees through
+     * DrawDisplayListOp's defer() or replay() methods
+     */
     template <class T>
-    inline void iterate(OpenGLRenderer& renderer, T& handler, const int level);
+    inline void issueOperations(OpenGLRenderer& renderer, T& handler);
 
     class TextContainer {
     public:
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 8ebffc2..fa82627 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -82,6 +82,8 @@
     // Returns true on success, false on failure
     void initialize();
 
+    bool hasContext();
+
     void usePBufferSurface();
     EGLSurface createSurface(EGLNativeWindowType window);
     void destroySurface(EGLSurface surface);
@@ -138,7 +140,7 @@
 }
 
 void GlobalContext::initialize() {
-    if (mEglDisplay != EGL_NO_DISPLAY) return;
+    if (hasContext()) return;
 
     mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
@@ -157,6 +159,10 @@
     initAtlas();
 }
 
+bool GlobalContext::hasContext() {
+    return mEglDisplay != EGL_NO_DISPLAY;
+}
+
 void GlobalContext::loadConfig() {
     EGLint swapBehavior = mCanSetDirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
     EGLint attribs[] = {
@@ -411,7 +417,6 @@
 
     Rect outBounds;
     status |= mCanvas->drawDisplayList(displayList, outBounds);
-    handleFunctorStatus(status, outBounds);
 
     // TODO: Draw debug info
     // TODO: Performance tracking
@@ -441,6 +446,15 @@
     mCanvas->detachFunctor(functor);
 }
 
+void CanvasContext::invokeFunctor(Functor* functor) {
+    DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
+    if (mGlobalContext->hasContext()) {
+        requireGlContext();
+        mode = DrawGlInfo::kModeProcess;
+    }
+    (*functor)(mode, NULL);
+}
+
 void CanvasContext::invokeFunctors() {
     mInvokeFunctorsPending = false;
 
@@ -448,22 +462,7 @@
 
     makeCurrent();
     Rect dirty;
-    int status = mCanvas->invokeFunctors(dirty);
-    handleFunctorStatus(status, dirty);
-}
-
-void CanvasContext::handleFunctorStatus(int status, const Rect& redrawClip) {
-    if (status & DrawGlInfo::kStatusDraw) {
-        // TODO: Invalidate the redrawClip
-        // Do we need to post to ViewRootImpl like the current renderer?
-        // Can we just enqueue ourselves to re-invoke the same display list?
-        // Something else entirely? Does ChromiumView still want this in a
-        // RenderThread world?
-    }
-
-    if (status & DrawGlInfo::kStatusInvoke) {
-        queueFunctorsTask();
-    }
+    mCanvas->invokeFunctors(dirty);
 }
 
 void CanvasContext::removeFunctorsTask() {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index e3fdf97..eb9096d 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -72,6 +72,7 @@
 
     void attachFunctor(Functor* functor);
     void detachFunctor(Functor* functor);
+    void invokeFunctor(Functor* functor);
 
     void runWithGlContext(RenderTask* task);
 
@@ -82,7 +83,6 @@
 
     friend class InvokeFunctorsTask;
     void invokeFunctors();
-    void handleFunctorStatus(int status, const Rect& redrawClip);
     void removeFunctorsTask();
     void queueFunctorsTask(int delayMs = FUNCTOR_PROCESS_DELAY);
 
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 16b93c3..cd711b0 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -167,6 +167,22 @@
     post(task);
 }
 
+CREATE_BRIDGE2(invokeFunctor, CanvasContext* context, Functor* functor) {
+    args->context->invokeFunctor(args->functor);
+    return NULL;
+}
+
+void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) {
+    SETUP_TASK(invokeFunctor);
+    args->context = mContext;
+    args->functor = functor;
+    if (waitForCompletion) {
+        postAndWait(task);
+    } else {
+        post(task);
+    }
+}
+
 CREATE_BRIDGE2(runWithGlContext, CanvasContext* context, RenderTask* task) {
     args->context->runWithGlContext(args->task);
     return NULL;
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index ee7a4c7..f1ca534 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -69,6 +69,7 @@
 
     ANDROID_API void attachFunctor(Functor* functor);
     ANDROID_API void detachFunctor(Functor* functor);
+    ANDROID_API void invokeFunctor(Functor* functor, bool waitForCompletion);
 
     ANDROID_API void runWithGlContext(RenderTask* task);
 
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 26e9cc5..04c6e97 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -56,7 +56,7 @@
     /** Default audio channel mask */
     public static final int CHANNEL_OUT_DEFAULT = 1;
 
-    // Channel mask definitions below are translated to the native values defined in
+    // Output channel mask definitions below are translated to the native values defined in
     //  in /system/core/include/system/audio.h in the JNI code of AudioTrack
     public static final int CHANNEL_OUT_FRONT_LEFT = 0x4;
     public static final int CHANNEL_OUT_FRONT_RIGHT = 0x8;
@@ -94,17 +94,21 @@
             CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER);
     public static final int CHANNEL_OUT_5POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
             CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT);
+    // different from AUDIO_CHANNEL_OUT_7POINT1
     public static final int CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
             CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
             CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER);
     /** @hide */
+    // matches AUDIO_CHANNEL_OUT_7POINT1
     public static final int CHANNEL_OUT_7POINT1_SURROUND = (
             CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_FRONT_RIGHT |
             CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT |
             CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
             CHANNEL_OUT_LOW_FREQUENCY);
+    // CHANNEL_OUT_ALL is not yet defined; if added then it should match AUDIO_CHANNEL_OUT_ALL
 
     public static final int CHANNEL_IN_DEFAULT = 1;
+    // These directly match native
     public static final int CHANNEL_IN_LEFT = 0x4;
     public static final int CHANNEL_IN_RIGHT = 0x8;
     public static final int CHANNEL_IN_FRONT = 0x10;
@@ -121,5 +125,8 @@
     public static final int CHANNEL_IN_VOICE_DNLINK = 0x8000;
     public static final int CHANNEL_IN_MONO = CHANNEL_IN_FRONT;
     public static final int CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT);
+    /** @hide */
+    public static final int CHANNEL_IN_FRONT_BACK = CHANNEL_IN_FRONT | CHANNEL_IN_BACK;
+    // CHANNEL_IN_ALL is not yet defined; if added then it should match AUDIO_CHANNEL_IN_ALL
 
 }
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index fe510f6..4bd5a80 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -43,6 +43,7 @@
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
+import android.hardware.usb.UsbManager;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
 import android.os.Binder;
@@ -528,6 +529,7 @@
         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
 
         intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
         // TODO merge orientation and rotation
@@ -1689,7 +1691,7 @@
     private static final String ASSET_FILE_VERSION = "1.0";
     private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
 
-    private static final int SOUND_EFECTS_LOAD_TIMEOUT_MS = 5000;
+    private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
 
     class LoadSoundEffectReply {
         public int mStatus = 1;
@@ -1801,7 +1803,7 @@
             sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
             while ((reply.mStatus == 1) && (attempts-- > 0)) {
                 try {
-                    reply.wait(SOUND_EFECTS_LOAD_TIMEOUT_MS);
+                    reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
                 } catch (InterruptedException e) {
                     Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
                 }
@@ -3289,7 +3291,7 @@
                 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
                     try {
                         // Wait for mSoundPoolCallBack to be set by the other thread
-                        mSoundEffectsLock.wait(SOUND_EFECTS_LOAD_TIMEOUT_MS);
+                        mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
                     } catch (InterruptedException e) {
                         Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
                     }
@@ -3353,7 +3355,7 @@
                     status = 1;
                     while ((status == 1) && (attempts-- > 0)) {
                         try {
-                            mSoundEffectsLock.wait(SOUND_EFECTS_LOAD_TIMEOUT_MS);
+                            mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
                             status = mSoundPoolCallBack.status();
                         } catch (InterruptedException e) {
                             Log.w(TAG, "Interrupted while waiting sound pool callback.");
@@ -3975,7 +3977,8 @@
                     (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) {
                 setBluetoothA2dpOnInt(true);
             }
-            boolean isUsb = ((device & AudioSystem.DEVICE_OUT_ALL_USB) != 0);
+            boolean isUsb = ((device & AudioSystem.DEVICE_OUT_ALL_USB) != 0) ||
+                            ((device & AudioSystem.DEVICE_IN_ALL_USB) != 0);
             handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
             if (state != 0) {
                 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
@@ -4083,18 +4086,31 @@
             } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ||
                            action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
                 state = intent.getIntExtra("state", 0);
+
                 int alsaCard = intent.getIntExtra("card", -1);
                 int alsaDevice = intent.getIntExtra("device", -1);
+                boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false);
+                boolean hasCapture = intent.getBooleanExtra("hasCapture", false);
+                boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false);
+
                 String params = (alsaCard == -1 && alsaDevice == -1 ? ""
                                     : "card=" + alsaCard + ";device=" + alsaDevice);
+
+                //TODO(pmclean) - Ignore for now the hasPlayback & hasCapture flags since we
+                // still need to call setWiredDeviceConnectionState() on disconnect (when we
+                // don't have card/device files to parse for this info). We will need to store
+                // that info here when we get smarter about multiple USB card/devices.
+                // Playback Device
                 device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
                         AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE;
-                Log.v(TAG, "Broadcast Receiver: Got "
-                        + (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
-                              "ACTION_USB_AUDIO_ACCESSORY_PLUG" : "ACTION_USB_AUDIO_DEVICE_PLUG")
-                        + ", state = " + state + ", card: " + alsaCard + ", device: " + alsaDevice);
                 setWiredDeviceConnectionState(device, state, params);
-            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
+
+                // Capture Device
+                device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
+                    AudioSystem.DEVICE_IN_USB_ACCESSORY : AudioSystem.DEVICE_IN_USB_DEVICE;
+                setWiredDeviceConnectionState(device, state, params);
+            }
+            else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
                 boolean broadcast = false;
                 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
                 synchronized (mScoClients) {
@@ -4199,7 +4215,7 @@
                         mStreamStates[AudioSystem.STREAM_MUSIC], 0);
             }
         }
-    }
+    } // end class AudioServiceBroadcastReceiver
 
     //==========================================================================================
     // RemoteControlDisplay / RemoteControlClient / Remote info
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 9c67bae..327c10c 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -288,6 +288,8 @@
                                              DEVICE_IN_USB_DEVICE |
                                              DEVICE_IN_DEFAULT);
     public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+    public static final int DEVICE_IN_ALL_USB = (DEVICE_IN_USB_ACCESSORY |
+                                                 DEVICE_IN_USB_DEVICE);
 
     // device states, must match AudioSystem::device_connection_state
     public static final int DEVICE_STATE_UNAVAILABLE = 0;
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 40c6797..57bc171 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1321,7 +1321,7 @@
      *
      * @param level send level scalar
      * @return error code or success, see {@link #SUCCESS},
-     *    {@link #ERROR_INVALID_OPERATION}
+     *    {@link #ERROR_INVALID_OPERATION}, {@link #ERROR}
      */
     public int setAuxEffectSendLevel(float level) {
         if (isRestricted()) {
@@ -1337,8 +1337,8 @@
         if (level > getMaxVolume()) {
             level = getMaxVolume();
         }
-        native_setAuxEffectSendLevel(level);
-        return SUCCESS;
+        int err = native_setAuxEffectSendLevel(level);
+        return err == 0 ? SUCCESS : ERROR;
     }
 
     //---------------------------------------------------------
@@ -1508,7 +1508,7 @@
             int sampleRateInHz, int channelConfig, int audioFormat);
 
     private native final int native_attachAuxEffect(int effectId);
-    private native final void native_setAuxEffectSendLevel(float level);
+    private native final int native_setAuxEffectSendLevel(float level);
 
     //---------------------------------------------------------
     // Utility methods
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 7170ffb..c016d08 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -1,4 +1,4 @@
-/*
+ /*
  * Copyright (C) 2013 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,11 +20,14 @@
 import java.util.UUID;
 import java.util.HashMap;
 import java.util.List;
+import android.os.Binder;
+import android.os.Debug;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
 import android.util.Log;
+import android.content.Context;
 
 /**
  * MediaDrm can be used to obtain keys for decrypting protected media streams, in
@@ -101,6 +104,20 @@
     private long mNativeContext;
 
     /**
+     * Specify no certificate type
+     *
+     * @hide - not part of the public API at this time
+     */
+    public static final int CERTIFICATE_TYPE_NONE = 0;
+
+    /**
+     * Specify X.509 certificate type
+     *
+     * @hide - not part of the public API at this time
+     */
+    public static final int CERTIFICATE_TYPE_X509 = 1;
+
+    /**
      * Query if the given scheme identified by its UUID is supported on
      * this device.
      * @param uuid The UUID of the crypto scheme.
@@ -316,6 +333,9 @@
      * Contains the opaque data an app uses to request keys from a license server
      */
     public final static class KeyRequest {
+        private byte[] mData;
+        private String mDefaultUrl;
+
         KeyRequest() {}
 
         /**
@@ -329,9 +349,6 @@
          * server URL from other sources.
          */
         public String getDefaultUrl() { return mDefaultUrl; }
-
-        private byte[] mData;
-        private String mDefaultUrl;
     };
 
     /**
@@ -456,7 +473,12 @@
      * is returned in ProvisionRequest.data. The recommended URL to deliver the provision
      * request to is returned in ProvisionRequest.defaultUrl.
      */
-    public native ProvisionRequest getProvisionRequest();
+    public ProvisionRequest getProvisionRequest() {
+        return getProvisionRequestNative(CERTIFICATE_TYPE_NONE, "");
+    }
+
+    private native ProvisionRequest getProvisionRequestNative(int certType,
+                                                              String certAuthority);
 
     /**
      * After a provision response is received by the app, it is provided to the DRM
@@ -468,7 +490,12 @@
      * @throws DeniedByServerException if the response indicates that the
      * server rejected the request
      */
-    public native void provideProvisionResponse(byte[] response)
+    public void provideProvisionResponse(byte[] response)
+        throws DeniedByServerException {
+        provideProvisionResponseNative(response);
+    }
+
+    private native Certificate provideProvisionResponseNative(byte[] response)
         throws DeniedByServerException;
 
     /**
@@ -683,6 +710,120 @@
         return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm);
     }
 
+    /**
+     * Contains the opaque data an app uses to request a certificate from a provisioning
+     * server
+     *
+     * @hide - not part of the public API at this time
+     */
+    public final static class CertificateRequest {
+        private byte[] mData;
+        private String mDefaultUrl;
+
+        CertificateRequest(byte[] data, String defaultUrl) {
+            mData = data;
+            mDefaultUrl = defaultUrl;
+        }
+
+        /**
+         * Get the opaque message data
+         */
+        public byte[] getData() { return mData; }
+
+        /**
+         * Get the default URL to use when sending the certificate request
+         * message to a server, if known. The app may prefer to use a different
+         * certificate server URL obtained from other sources.
+         */
+        public String getDefaultUrl() { return mDefaultUrl; }
+    }
+
+    /**
+     * Generate a certificate request, specifying the certificate type
+     * and authority. The response received should be passed to
+     * provideCertificateResponse.
+     *
+     * @param certType Specifies the certificate type.
+     *
+     * @param certAuthority is passed to the certificate server to specify
+     * the chain of authority.
+     *
+     * @hide - not part of the public API at this time
+     */
+    public CertificateRequest getCertificateRequest(int certType,
+                                                    String certAuthority)
+    {
+        ProvisionRequest provisionRequest = getProvisionRequestNative(certType, certAuthority);
+        return new CertificateRequest(provisionRequest.getData(),
+                                      provisionRequest.getDefaultUrl());
+    }
+
+    /**
+     * Contains the wrapped private key and public certificate data associated
+     * with a certificate.
+     *
+     * @hide - not part of the public API at this time
+     */
+    public final static class Certificate {
+        Certificate() {}
+
+        /**
+         * Get the wrapped private key data
+         */
+        public byte[] getWrappedPrivateKey() { return mWrappedKey; }
+
+        /**
+         * Get the PEM-encoded certificate chain
+         */
+        public byte[] getContent() { return mCertificateData; }
+
+        private byte[] mWrappedKey;
+        private byte[] mCertificateData;
+    }
+
+
+    /**
+     * Process a response from the certificate server.  The response
+     * is obtained from an HTTP Post to the url provided by getCertificateRequest.
+     * <p>
+     * The public X509 certificate chain and wrapped private key are returned
+     * in the returned Certificate objec.  The certificate chain is in PEM format.
+     * The wrapped private key should be stored in application private
+     * storage, and used when invoking the signRSA method.
+     *
+     * @param response the opaque certificate response byte array to provide to the
+     * DRM engine plugin.
+     *
+     * @throws DeniedByServerException if the response indicates that the
+     * server rejected the request
+     *
+     * @hide - not part of the public API at this time
+     */
+    public Certificate provideCertificateResponse(byte[] response)
+        throws DeniedByServerException {
+        return provideProvisionResponseNative(response);
+    }
+
+    private static final native byte[] signRSANative(MediaDrm drm, byte[] sessionId,
+                                                     String algorithm, byte[] wrappedKey,
+                                                     byte[] message);
+
+    /**
+     * Sign data using an RSA key
+     *
+     * @param context the app context
+     * @param sessionId a sessionId obtained from openSession on the MediaDrm object
+     * @param algorithm the signing algorithm to use, e.g. "PKCS1-BlockType1"
+     * @param wrappedKey - the wrapped (encrypted) RSA private key obtained
+     * from provideCertificateResponse
+     * @param message the data for which a signature is to be computed
+     *
+     * @hide - not part of the public API at this time
+     */
+    public byte[] signRSA(Context context, byte[] sessionId, String algorithm, byte[] wrappedKey, byte[] message) {
+        return signRSANative(this, sessionId, algorithm, wrappedKey, message);
+    }
+
     @Override
     protected void finalize() {
         native_finalize();
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 15ae238..fce3fd0 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -202,12 +202,17 @@
     public void setServer(MtpServer server) {
         mServer = server;
 
+        // always unregister before registering
+        try {
+            mContext.unregisterReceiver(mBatteryReceiver);
+        } catch (IllegalArgumentException e) {
+            // wasn't previously registered, ignore
+        }
+
         // register for battery notifications when we are connected
         if (server != null) {
             mContext.registerReceiver(mBatteryReceiver,
                     new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
-        } else {
-            mContext.unregisterReceiver(mBatteryReceiver);
         }
     }
 
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index b2fb2df..d04b1f8 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -27,6 +27,8 @@
 #include "jni.h"
 #include "JNIHelp.h"
 
+#include <cutils/compiler.h>
+
 #include <gui/Surface.h>
 
 #include <media/ICrypto.h>
@@ -738,6 +740,10 @@
     } else if (numBytesOfClearDataObj != NULL
             && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
         err = -ERANGE;
+    // subSamples array may silently overflow if number of samples are too large.  Use
+    // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
+    } else if ( CC_UNLIKELY(numSubSamples >= INT32_MAX / sizeof(*subSamples)) ) {
+        err = -EINVAL;
     } else {
         jboolean isCopy;
 
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 052d97d..1dbaa3a 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -100,6 +100,16 @@
     jint kKeyTypeRelease;
 } gKeyTypes;
 
+struct CertificateTypes {
+    jint kCertificateTypeNone;
+    jint kCertificateTypeX509;
+} gCertificateTypes;
+
+struct CertificateFields {
+    jfieldID wrappedPrivateKey;
+    jfieldID certificateData;
+};
+
 struct fields_t {
     jfieldID context;
     jmethodID post_event;
@@ -110,6 +120,11 @@
     SetFields set;
     IteratorFields iterator;
     EntryFields entry;
+    CertificateFields certificate;
+    jclass certificateClassId;
+    jclass hashmapClassId;
+    jclass arraylistClassId;
+    jclass stringClassId;
 };
 
 static fields_t gFields;
@@ -406,8 +421,7 @@
 */
 
 static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) {
-    jclass clazz;
-    FIND_CLASS(clazz, "java/lang/String");
+    jclass clazz = gFields.stringClassId;
     KeyedVector<String8, String8> keyedVector;
 
     jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
@@ -450,8 +464,7 @@
 }
 
 static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
-    jclass clazz;
-    FIND_CLASS(clazz, "java/util/HashMap");
+    jclass clazz = gFields.hashmapClassId;
     jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
     for (size_t i = 0; i < map.size(); ++i) {
         jstring jkey = env->NewStringUTF(map.keyAt(i).string());
@@ -465,8 +478,7 @@
 
 static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
                                                    List<Vector<uint8_t> > list) {
-    jclass clazz;
-    FIND_CLASS(clazz, "java/util/ArrayList");
+    jclass clazz = gFields.arraylistClassId;
     jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
     List<Vector<uint8_t> >::iterator iter = list.begin();
     while (iter != list.end()) {
@@ -542,6 +554,11 @@
     GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
     gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
 
+    GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
+    gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
+    GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
+    gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
+
     FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
     GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
     GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
@@ -550,6 +567,11 @@
     GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
     GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
 
+    FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
+    GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
+    GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
+    gFields.certificateClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz));
+
     FIND_CLASS(clazz, "java/util/ArrayList");
     GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
     GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
@@ -571,6 +593,15 @@
     FIND_CLASS(clazz, "java/util/Map$Entry");
     GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
     GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
+
+    FIND_CLASS(clazz, "java/util/HashMap");
+    gFields.hashmapClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz));
+
+    FIND_CLASS(clazz, "java/lang/String");
+    gFields.stringClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz));
+
+    FIND_CLASS(clazz, "java/util/ArrayList");
+    gFields.arraylistClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz));
 }
 
 static void android_media_MediaDrm_native_setup(
@@ -826,8 +857,8 @@
     return KeyedVectorToHashMap(env, infoMap);
 }
 
-static jobject android_media_MediaDrm_getProvisionRequest(
-    JNIEnv *env, jobject thiz) {
+static jobject android_media_MediaDrm_getProvisionRequestNative(
+    JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
     sp<IDrm> drm = GetDrm(env, thiz);
 
     if (drm == NULL) {
@@ -839,7 +870,17 @@
     Vector<uint8_t> request;
     String8 defaultUrl;
 
-    status_t err = drm->getProvisionRequest(request, defaultUrl);
+    String8 certType;
+    if (jcertType == gCertificateTypes.kCertificateTypeX509) {
+        certType = "X.509";
+    } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
+        certType = "none";
+    } else {
+        certType = "invalid";
+    }
+
+    String8 certAuthority = JStringToString8(env, jcertAuthority);
+    status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
 
     if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
         return NULL;
@@ -863,27 +904,43 @@
     return provisionObj;
 }
 
-static void android_media_MediaDrm_provideProvisionResponse(
+static jobject android_media_MediaDrm_provideProvisionResponseNative(
     JNIEnv *env, jobject thiz, jbyteArray jresponse) {
     sp<IDrm> drm = GetDrm(env, thiz);
 
     if (drm == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
                           "MediaDrm obj is null");
-        return;
+        return NULL;
     }
 
     if (jresponse == NULL) {
         jniThrowException(env, "java/lang/IllegalArgumentException",
                           "provision response is null");
-        return;
+        return NULL;
     }
 
     Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
+    Vector<uint8_t> certificate, wrappedKey;
 
-    status_t err = drm->provideProvisionResponse(response);
+    status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
+
+    // Fill out return obj
+    jclass clazz = gFields.certificateClassId;
+
+    jobject certificateObj = NULL;
+
+    if (clazz && certificate.size() && wrappedKey.size()) {
+        certificateObj = env->AllocObject(clazz);
+        jbyteArray jcertificate = VectorToJByteArray(env, certificate);
+        env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
+
+        jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
+        env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
+    }
 
     throwExceptionAsNecessary(env, err, "Failed to handle provision response");
+    return certificateObj;
 }
 
 static jobject android_media_MediaDrm_getSecureStops(
@@ -1209,6 +1266,38 @@
 }
 
 
+static jbyteArray android_media_MediaDrm_signRSANative(
+    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+    jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
+
+    sp<IDrm> drm = GetDrm(env, jdrm);
+
+    if (!CheckSession(env, drm, jsessionId)) {
+        return NULL;
+    }
+
+    if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException",
+                          "required argument is null");
+        return NULL;
+    }
+
+    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+    String8 algorithm = JStringToString8(env, jalgorithm);
+    Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
+    Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
+    Vector<uint8_t> signature;
+
+    status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
+
+    if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
+        return NULL;
+    }
+
+    return VectorToJByteArray(env, signature);
+}
+
+
 static JNINativeMethod gMethods[] = {
     { "release", "()V", (void *)android_media_MediaDrm_release },
     { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
@@ -1244,11 +1333,11 @@
     { "queryKeyStatus", "([B)Ljava/util/HashMap;",
       (void *)android_media_MediaDrm_queryKeyStatus },
 
-    { "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;",
-      (void *)android_media_MediaDrm_getProvisionRequest },
+    { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
+      (void *)android_media_MediaDrm_getProvisionRequestNative },
 
-    { "provideProvisionResponse", "([B)V",
-      (void *)android_media_MediaDrm_provideProvisionResponse },
+    { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
+      (void *)android_media_MediaDrm_provideProvisionResponseNative },
 
     { "getSecureStops", "()Ljava/util/List;",
       (void *)android_media_MediaDrm_getSecureStops },
@@ -1287,6 +1376,9 @@
 
     { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
       (void *)android_media_MediaDrm_verifyNative },
+
+    { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
+      (void *)android_media_MediaDrm_signRSANative },
 };
 
 int register_android_media_Drm(JNIEnv *env) {
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index a78f16d..3dbf77b 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -87,7 +87,7 @@
         jbyteArray byteArrayObj = env->NewByteArray(size);
         env->DeleteLocalRef(env->GetObjectClass(mDataSource));
         env->DeleteLocalRef(env->GetObjectClass(byteArrayObj));
-        ssize_t numread = env->CallIntMethod(mDataSource, mReadMethod, offset, byteArrayObj, size);
+        ssize_t numread = env->CallIntMethod(mDataSource, mReadMethod, offset, byteArrayObj, (jint)size);
         env->GetByteArrayRegion(byteArrayObj, 0, size, (jbyte*) buffer);
         env->DeleteLocalRef(byteArrayObj);
         if (env->ExceptionCheck()) {
@@ -632,7 +632,7 @@
     env->CallVoidMethod(
             cryptoInfoObj,
             gFields.cryptoInfoSetID,
-            numSubSamples,
+            (jint)numSubSamples,
             numBytesOfPlainDataObj,
             numBytesOfEncryptedDataObj,
             keyObj,
diff --git a/media/lib/Android.mk b/media/lib/remotedisplay/Android.mk
similarity index 93%
rename from media/lib/Android.mk
rename to media/lib/remotedisplay/Android.mk
index 50799a6..ea1ac2b 100644
--- a/media/lib/Android.mk
+++ b/media/lib/remotedisplay/Android.mk
@@ -15,7 +15,7 @@
 #
 LOCAL_PATH := $(call my-dir)
 
-# the library
+# the remotedisplay library
 # ============================================================
 include $(CLEAR_VARS)
 
@@ -23,7 +23,7 @@
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := \
-            $(call all-subdir-java-files) \
+            $(call all-java-files-under, java) \
             $(call all-aidl-files-under, java)
 
 include $(BUILD_JAVA_LIBRARY)
diff --git a/media/lib/README.txt b/media/lib/remotedisplay/README.txt
similarity index 99%
rename from media/lib/README.txt
rename to media/lib/remotedisplay/README.txt
index cade3df..5738dbe 100644
--- a/media/lib/README.txt
+++ b/media/lib/remotedisplay/README.txt
@@ -25,4 +25,3 @@
 library is a compromise to make new capabilities available to the system
 without exposing the full surface area of the support library media
 route provider protocol.
-
diff --git a/media/lib/com.android.media.remotedisplay.xml b/media/lib/remotedisplay/com.android.media.remotedisplay.xml
similarity index 100%
rename from media/lib/com.android.media.remotedisplay.xml
rename to media/lib/remotedisplay/com.android.media.remotedisplay.xml
diff --git a/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java
similarity index 100%
rename from media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java
rename to media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java
diff --git a/media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
similarity index 100%
rename from media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
rename to media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
diff --git a/media/lib/Android.mk b/media/lib/signer/Android.mk
similarity index 76%
copy from media/lib/Android.mk
copy to media/lib/signer/Android.mk
index 50799a6..4c3772f 100644
--- a/media/lib/Android.mk
+++ b/media/lib/signer/Android.mk
@@ -15,24 +15,23 @@
 #
 LOCAL_PATH := $(call my-dir)
 
-# the library
+# the mediadrm signer library
 # ============================================================
 include $(CLEAR_VARS)
 
-LOCAL_MODULE:= com.android.media.remotedisplay
+LOCAL_MODULE:= com.android.mediadrm.signer
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := \
-            $(call all-subdir-java-files) \
-            $(call all-aidl-files-under, java)
+            $(call all-java-files-under, java)
 
-include $(BUILD_JAVA_LIBRARY)
+include $(BUILD_STATIC_JAVA_LIBRARY)
 
 
-# ====  com.android.media.remotedisplay.xml lib def  ========================
+# ====  com.android.mediadrm.signer.xml lib def  ========================
 include $(CLEAR_VARS)
 
-LOCAL_MODULE := com.android.media.remotedisplay.xml
+LOCAL_MODULE := com.android.mediadrm.signer.xml
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_MODULE_CLASS := ETC
diff --git a/media/lib/signer/README.txt b/media/lib/signer/README.txt
new file mode 100644
index 0000000..362ab8e
--- /dev/null
+++ b/media/lib/signer/README.txt
@@ -0,0 +1,28 @@
+This library (com.android.mediadrm.signer.jar) is a shared java library
+containing classes required by unbundled apps running on devices that use
+the certficate provisioning and private key signing capabilities provided
+by the MediaDrm API.
+
+--- Rules of this library ---
+o This library is effectively a PUBLIC API for unbundled CAST receivers
+  that may be distributed outside the system image. So it MUST BE API STABLE.
+  You can add but not remove. The rules are the same as for the
+  public platform SDK API.
+o This library can see and instantiate internal platform classes, but it must not
+  expose them in any public method (or by extending them via inheritance). This would
+  break clients of the library because they cannot see the internal platform classes.
+
+This library is distributed in the system image, and loaded as
+a shared library. So you can change the implementation, but not
+the interface. In this way it is like framework.jar.
+
+--- Why does this library exist? ---
+
+Unbundled apps cannot use internal platform classes.
+
+This library will eventually be replaced when the provisioned certificate-
+based signing infrastructure that is currently defined in the support library
+is reintegrated with the framework in a new API.  That API isn't ready yet so
+this library is a compromise to make new capabilities available to the system
+without exposing the full surface area of the support library.
+
diff --git a/media/lib/signer/com.android.mediadrm.signer.xml b/media/lib/signer/com.android.mediadrm.signer.xml
new file mode 100644
index 0000000..b5b1f09
--- /dev/null
+++ b/media/lib/signer/com.android.mediadrm.signer.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<permissions>
+    <library name="com.android.media.drm.signer"
+            file="/system/framework/com.android.media.drm.signer.jar" />
+</permissions>
diff --git a/media/lib/signer/java/com/android/mediadrm/signer/MediaDrmSigner.java b/media/lib/signer/java/com/android/mediadrm/signer/MediaDrmSigner.java
new file mode 100644
index 0000000..d971afb
--- /dev/null
+++ b/media/lib/signer/java/com/android/mediadrm/signer/MediaDrmSigner.java
@@ -0,0 +1,139 @@
+/*
+ * 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 com.android.mediadrm.signer;
+
+import android.content.Context;
+import android.media.MediaDrm;
+import android.media.DeniedByServerException;
+
+/**
+ * Provides certificate request generation, response handling and
+ * signing APIs
+ */
+public final class MediaDrmSigner {
+    private MediaDrmSigner() {}
+
+    /**
+     * Specify X.509 certificate type
+     */
+    public static final int CERTIFICATE_TYPE_X509 = MediaDrm.CERTIFICATE_TYPE_X509;
+
+    /**
+     * Contains the opaque data an app uses to request a certificate from a provisioning
+     * server
+     */
+    public final static class CertificateRequest {
+        private MediaDrm.CertificateRequest mCertRequest;
+
+        CertificateRequest(MediaDrm.CertificateRequest certRequest) {
+            mCertRequest = certRequest;
+        }
+
+        /**
+         * Get the opaque message data
+         */
+        public byte[] getData() {
+            return mCertRequest.getData();
+        }
+
+        /**
+         * Get the default URL to use when sending the certificate request
+         * message to a server, if known. The app may prefer to use a different
+         * certificate server URL obtained from other sources.
+         */
+        public String getDefaultUrl() {
+            return mCertRequest.getDefaultUrl();
+        }
+    }
+
+    /**
+     * Contains the wrapped private key and public certificate data associated
+     * with a certificate.
+     */
+    public final static class Certificate {
+        private MediaDrm.Certificate mCertificate;
+
+        Certificate(MediaDrm.Certificate certificate) {
+            mCertificate = certificate;
+        }
+
+        /**
+         * Get the wrapped private key data
+         */
+        public byte[] getWrappedPrivateKey() {
+            return mCertificate.getWrappedPrivateKey();
+        }
+
+        /**
+         * Get the PEM-encoded public certificate chain
+         */
+        public byte[] getContent() {
+            return mCertificate.getContent();
+        }
+    }
+
+    /**
+     * Generate a certificate request, specifying the certificate type
+     * and authority. The response received should be passed to
+     * provideCertificateResponse.
+     *
+     * @param drm the MediaDrm object
+     * @param certType Specifies the certificate type.
+     * @param certAuthority is passed to the certificate server to specify
+     * the chain of authority.
+     */
+    public static CertificateRequest getCertificateRequest(MediaDrm drm, int certType,
+                                                           String certAuthority) {
+        return new CertificateRequest(drm.getCertificateRequest(certType, certAuthority));
+    }
+
+    /**
+     * Process a response from the provisioning server.  The response
+     * is obtained from an HTTP Post to the url provided by getCertificateRequest.
+     *
+     * The public X509 certificate chain and wrapped private key are returned
+     * in the returned Certificate objec.  The certificate chain is in BIO serialized
+     * PEM format.  The wrapped private key should be stored in application private
+     * storage, and used when invoking the signRSA method.
+     *
+     * @param drm the MediaDrm object
+     * @param response the opaque certificate response byte array to provide to the
+     * DRM engine plugin.
+     * @throws android.media.DeniedByServerException if the response indicates that the
+     * server rejected the request
+     */
+    public static Certificate provideCertificateResponse(MediaDrm drm, byte[] response)
+        throws DeniedByServerException {
+        return new Certificate(drm.provideCertificateResponse(response));
+    }
+
+    /**
+     * Sign data using an RSA key
+     *
+     * @param context the App context
+     * @param drm the MediaDrm object
+     * @param sessionId a sessionId obtained from openSession on the MediaDrm object
+     * @param algorithm the signing algorithm to use, e.g. "PKCS1-BlockType1"
+     * @param wrappedKey - the wrapped (encrypted) RSA private key obtained
+     * from provideCertificateResponse
+     * @param message the data for which a signature is to be computed
+     */
+    public static byte[] signRSA(Context context, MediaDrm drm, byte[] sessionId,
+                                 String algorithm, byte[] wrappedKey, byte[] message) {
+        return drm.signRSA(context, sessionId, algorithm, wrappedKey, message);
+    }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 43ebef4..5f3ba74 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -140,7 +140,9 @@
 
     private int submitCameraRequest(CaptureRequest request, boolean streaming) throws Exception {
         int requestId = mCameraUser.submitRequest(request, streaming);
-        assertTrue("Request IDs should be non-negative", requestId >= 0);
+        assertTrue(
+                "Request IDs should be non-negative (expected: >= 0, actual: " + requestId + ")",
+                requestId >= 0);
         return requestId;
     }
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index 3f17aa9..26498ca 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -309,7 +309,7 @@
                 });
 
         // rational (n) -- in particular rational x 9
-        checkKeyGetAndSetArray("android.sensor.calibrationTransform1", Rational[].class,
+        checkKeyGetAndSetArray("android.sensor.calibrationTransform", Rational[].class,
                 new Rational[] {
                         new Rational(1, 2), new Rational(3, 4), new Rational(5, 6),
                         new Rational(7, 8), new Rational(9, 10), new Rational(10, 11),
diff --git a/media/tests/omxjpegdecoder/Android.mk b/media/tests/omxjpegdecoder/Android.mk
index 95ae33b..b0bc5d4 100644
--- a/media/tests/omxjpegdecoder/Android.mk
+++ b/media/tests/omxjpegdecoder/Android.mk
@@ -19,7 +19,6 @@
 LOCAL_SRC_FILES := \
         omx_jpeg_decoder.cpp \
         jpeg_decoder_bench.cpp \
-        SkOmxPixelRef.cpp \
         StreamSource.cpp
 
 LOCAL_SHARED_LIBRARIES := \
diff --git a/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp b/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp
deleted file mode 100644
index a25e854..0000000
--- a/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <SkBitmap.h>
-
-#include "SkOmxPixelRef.h"
-
-using namespace android;
-
-SkOmxPixelRef::SkOmxPixelRef(SkColorTable* ctable, MediaBuffer* buffer,
-        sp<MediaSource> decoder)  {
-    mBuffer = buffer;
-    mDecoder = decoder;
-    mSize = buffer->size();
-    mCTable = ctable;
-    SkSafeRef(mCTable);
-}
-
-SkOmxPixelRef::~SkOmxPixelRef() {
-    mBuffer->release();
-    CHECK_EQ(mDecoder->stop(), (status_t)OK);
-    SkSafeUnref(mCTable);
-}
-
-void* SkOmxPixelRef::onLockPixels(SkColorTable** ct) {
-    *ct = mCTable;
-    return mBuffer->data();
-}
-
-void SkOmxPixelRef::onUnlockPixels() {
-    // nothing to do
-}
diff --git a/media/tests/omxjpegdecoder/SkOmxPixelRef.h b/media/tests/omxjpegdecoder/SkOmxPixelRef.h
deleted file mode 100644
index 374604c..0000000
--- a/media/tests/omxjpegdecoder/SkOmxPixelRef.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SKOMXPIXELREF_DEFINED
-#define SKOMXPIXELREF_DEFINED
-
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
-#include <SkPixelRef.h>
-
-namespace android {
-
-class SkOmxPixelRef : public SkPixelRef {
-public:
-    SkOmxPixelRef(SkColorTable* ctable, MediaBuffer* buffer,
-            sp<MediaSource> decoder);
-    virtual ~SkOmxPixelRef();
-
-     //! Return the allocation size for the pixels
-    size_t getSize() const { return mSize; }
-
-    SK_DECLARE_UNFLATTENABLE_OBJECT()
-protected:
-    // overrides from SkPixelRef
-    virtual void* onLockPixels(SkColorTable**);
-    virtual void onUnlockPixels();
-
-private:
-    MediaBuffer* mBuffer;
-    sp<MediaSource> mDecoder;
-    size_t          mSize;
-    SkColorTable*   mCTable;
-
-    typedef SkPixelRef INHERITED;
-};
-
-} // namespace android
-#endif // SKOMXPIXELREF_DEFINED
diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
index 53f04bc..3dd988e 100644
--- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
+++ b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
@@ -34,7 +34,6 @@
 #include <SkMallocPixelRef.h>
 
 #include "omx_jpeg_decoder.h"
-#include "SkOmxPixelRef.h"
 #include "StreamSource.h"
 
 using namespace android;
@@ -158,10 +157,6 @@
     printf("Duration in decoder->read(): %.1f (msecs). \n",
                 duration / 1E3 );
 
-    /* Mark the code for now, since we attend to copy buffer to SkBitmap.
-    // Install pixelRef to Bitmap.
-    installPixelRef(buffer, decoder, bm);*/
-
     // Copy pixels from buffer to bm.
     // May need to check buffer->rawBytes() == bm->rawBytes().
     CHECK_EQ(buffer->size(), bm->getSize());
@@ -172,17 +167,6 @@
     return true;
 }
 
-void OmxJpegImageDecoder::installPixelRef(MediaBuffer *buffer, sp<MediaSource> decoder,
-        SkBitmap* bm) {
-
-    // set bm's pixelref based on the data in buffer.
-    SkAutoLockPixels alp(*bm);
-    SkPixelRef* pr = new SkOmxPixelRef(NULL, buffer, decoder);
-    bm->setPixelRef(pr)->unref();
-    bm->lockPixels();
-    return;
-}
-
 void OmxJpegImageDecoder::configBitmapSize(SkBitmap* bm, SkBitmap::Config pref,
         int width, int height) {
     bm->setConfig(getColorSpaceConfig(pref), width, height, 0, kOpaque_SkAlphaType);
diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.h b/media/tests/omxjpegdecoder/omx_jpeg_decoder.h
index a313877..e431e72 100644
--- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.h
+++ b/media/tests/omxjpegdecoder/omx_jpeg_decoder.h
@@ -49,8 +49,6 @@
     sp<MediaSource> getDecoder(OMXClient* client, const sp<MediaSource>& source);
     bool decodeSource(sp<MediaSource> decoder, const sp<MediaSource>& source,
             SkBitmap* bm);
-    void installPixelRef(MediaBuffer* buffer, sp<MediaSource> decoder,
-            SkBitmap* bm);
     void configBitmapSize(SkBitmap* bm, SkBitmap::Config pref, int width,
             int height);
     SkBitmap::Config getColorSpaceConfig(SkBitmap::Config pref);
diff --git a/packages/InputDevices/res/raw/keyboard_layout_arabic.kcm b/packages/InputDevices/res/raw/keyboard_layout_arabic.kcm
new file mode 100644
index 0000000..2a95cfe
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_arabic.kcm
@@ -0,0 +1,319 @@
+# 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.
+
+#
+# Arabic (US-101 keys) keyboard layout.
+#
+
+type OVERLAY
+
+### ROW 1
+
+key GRAVE {
+    label:                              '`'
+    base, capslock:                     '\u0630'
+    shift:                              '\u0651'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '\u0661'
+    shift:                              '!'
+    capslock:                           '1'
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '\u0662'
+    shift:                              '@'
+    capslock:                           '2'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '\u0663'
+    shift:                              '#'
+    capslock:                           '3'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '\u0664'
+    shift:                              '$'
+    capslock:                           '4'
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '\u0665'
+    shift:                              '%'
+    capslock:                           '5'
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '\u0666'
+    shift:                              '^'
+    capslock:                           '6'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '\u0667'
+    shift:                              '&'
+    capslock:                           '7'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '\u0668'
+    shift:                              '*'
+    capslock:                           '8'
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '\u0669'
+    shift:                              '('
+    capslock:                           '9'
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '\u0660'
+    shift:                              ')'
+    capslock:                           '0'
+}
+
+key MINUS {
+    label:                              '-'
+    base, capslock:                     '-'
+    shift:                              '_'
+}
+
+key EQUALS {
+    label:                              '='
+    base, capslock:                     '='
+    shift:                              '+'
+}
+
+### ROW 2
+
+key Q {
+    label:                              'Q'
+    base, capslock:                     '\u0636'
+    shift:                              '\u064e'
+}
+
+key W {
+    label:                              'W'
+    base, capslock:                     '\u0635'
+    shift:                              '\u064b'
+}
+
+key E {
+    label:                              'E'
+    base, capslock:                     '\u062b'
+    shift:                              '\u064f'
+}
+
+key R {
+    label:                              'R'
+    base, capslock:                     '\u0642'
+    shift:                              '\u064c'
+}
+
+key T {
+    label:                              'T'
+    base, capslock:                     '\u0641'
+    shift:                              '\ufef9'
+}
+
+key Y {
+    label:                              'Y'
+    base, capslock:                     '\u063a'
+    shift:                              '\u0625'
+}
+
+key U {
+    label:                              'U'
+    base, capslock:                     '\u0639'
+    shift:                              '\u2018'
+}
+
+key I {
+    label:                              'I'
+    base, capslock:                     '\u0647'
+    shift:                              '\u00f7'
+}
+
+key O {
+    label:                              'O'
+    base, capslock:                     '\u062e'
+    shift:                              '\u00d7'
+}
+
+key P {
+    label:                              'P'
+    base, capslock:                     '\u062d'
+    shift:                              '\u061b'
+}
+
+key LEFT_BRACKET {
+    label:                              '['
+    base, capslock:                     '\u062c'
+    shift:                              '<'
+}
+
+key RIGHT_BRACKET {
+    label:                              ']'
+    base, capslock:                     '\u062f'
+    shift:                              '>'
+}
+
+key BACKSLASH {
+    label:                              '\\'
+    base, capslock:                     '\\'
+    shift:                              '|'
+}
+
+### ROW 3
+
+key A {
+    label:                              'A'
+    base, capslock:                     '\u0634'
+    shift:                              '\u0650'
+}
+
+key S {
+    label:                              'S'
+    base, capslock:                     '\u0633'
+    shift:                              '\u064d'
+}
+
+key D {
+    label:                              'D'
+    base, capslock:                     '\u064a'
+    shift:                              ']'
+}
+
+key F {
+    label:                              'F'
+    base, capslock:                     '\u0628'
+    shift:                              '['
+}
+
+key G {
+    label:                              'G'
+    base, capslock:                     '\u0644'
+    shift:                              '\ufef7'
+}
+
+key H {
+    label:                              'H'
+    base, capslock:                     '\u0627'
+    shift:                              '\u0623'
+}
+
+key J {
+    label:                              'J'
+    base, capslock:                     '\u062a'
+    shift:                              '\u0640'
+}
+
+key K {
+    label:                              'K'
+    base, capslock:                     '\u0646'
+    shift:                              '\u060c'
+}
+
+key L {
+    label:                              'L'
+    base, capslock:                     '\u0645'
+    shift:                              '/'
+}
+
+key SEMICOLON {
+    label:                              ';'
+    base, capslock:                     '\u0643'
+    shift:                              ':'
+}
+
+key APOSTROPHE {
+    label:                              '\''
+    base, capslock:                     '\u0637'
+    shift:                              '"'
+}
+
+### ROW 4
+
+key Z {
+    label:                              'Z'
+    base, capslock:                     '\u0626'
+    shift:                              '~'
+}
+
+key X {
+    label:                              'X'
+    base, capslock:                     '\u0621'
+    shift:                              '\u0652'
+}
+
+key C {
+    label:                              'C'
+    base, capslock:                     '\u0624'
+    shift:                              '}'
+}
+
+key V {
+    label:                              'V'
+    base, capslock:                     '\u0631'
+    shift:                              '{'
+}
+
+key B {
+    label:                              'B'
+    base, capslock:                     '\ufefb'
+    shift:                              '\ufef5'
+}
+
+key N {
+    label:                              'N'
+    base, capslock:                     '\u0649'
+    shift:                              '\u0622'
+}
+
+key M {
+    label:                              'M'
+    base, capslock:                     '\u0629'
+    shift:                              '\u2019'
+}
+
+key COMMA {
+    label:                              ','
+    base, capslock:                     '\u0648'
+    shift:                              ','
+}
+
+key PERIOD {
+    label:                              '.'
+    base, capslock:                     '\u0632'
+    shift:                              '.'
+}
+
+key SLASH {
+    label:                              '/'
+    base, capslock:                     '\u0638'
+    shift:                              '\u061f'
+}
diff --git a/packages/InputDevices/res/raw/keyboard_layout_greek.kcm b/packages/InputDevices/res/raw/keyboard_layout_greek.kcm
new file mode 100644
index 0000000..a7684e1
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_greek.kcm
@@ -0,0 +1,338 @@
+# 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.
+
+#
+# Greek (EU based) keyboard layout.
+#
+
+type OVERLAY
+
+map key 86 PLUS
+
+### ROW 1
+
+key GRAVE {
+    label:                              '`'
+    base, capslock:                     '`'
+    shift:                              '~'
+}
+
+key 1 {
+    label:                              '1'
+    base, capslock:                     '1'
+    shift:                              '!'
+}
+
+key 2 {
+    label:                              '2'
+    base, capslock:                     '2'
+    shift:                              '@'
+    ralt:                               '\u00b2'
+}
+
+key 3 {
+    label:                              '3'
+    base, capslock:                     '3'
+    shift:                              '#'
+    ralt:                               '\u00b3'
+}
+
+key 4 {
+    label:                              '4'
+    base, capslock:                     '4'
+    shift:                              '$'
+    ralt:                               '\u00a3'
+}
+
+key 5 {
+    label:                              '5'
+    base, capslock:                     '5'
+    shift:                              '%'
+    ralt:                               '\u00a7'
+}
+
+key 6 {
+    label:                              '6'
+    base, capslock:                     '6'
+    shift:                              '^'
+    ralt:                               '\u00b6'
+}
+
+key 7 {
+    label:                              '7'
+    base, capslock:                     '7'
+    shift:                              '&'
+}
+
+key 8 {
+    label:                              '8'
+    base, capslock:                     '8'
+    shift:                              '*'
+    ralt:                               '\u00a4'
+}
+
+key 9 {
+    label:                              '9'
+    base, capslock:                     '9'
+    shift:                              '('
+    ralt:                               '\u00a6'
+}
+
+key 0 {
+    label:                              '0'
+    base, capslock:                     '0'
+    shift:                              ')'
+    ralt:                               '\u00b0'
+}
+
+key MINUS {
+    label:                              '-'
+    base, capslock:                     '-'
+    shift:                              '_'
+    ralt:                               '\u00b1'
+}
+
+key EQUALS {
+    label:                              '='
+    base, capslock:                     '='
+    shift:                              '+'
+    ralt:                               '\u00bd'
+}
+
+### ROW 2
+
+key Q {
+    label:                              'Q'
+    base, capslock:                     ';'
+    shift:                              ':'
+}
+
+key W {
+    label:                              'W'
+    base, capslock:                     '\u03c2'
+    shift:                              '\u0385'
+}
+
+key E {
+    label:                              'E'
+    base:                               '\u03b5'
+    shift, capslock:                    '\u0395'
+    ralt:                               '\u20ac'
+}
+
+key R {
+    label:                              'R'
+    base:                               '\u03c1'
+    shift, capslock:                    '\u03a1'
+    ralt:                               '\u00ae'
+}
+
+key T {
+    label:                              'T'
+    base:                               '\u03c4'
+    shift, capslock:                    '\u03a4'
+}
+
+key Y {
+    label:                              'Y'
+    base:                               '\u03c5'
+    shift, capslock:                    '\u03a5'
+    ralt:                               '\u00a5'
+}
+
+key U {
+    label:                              'U'
+    base:                               '\u03b8'
+    shift, capslock:                    '\u0398'
+}
+
+key I {
+    label:                              'I'
+    base:                               '\u03b9'
+    shift, capslock:                    '\u0399'
+}
+
+key O {
+    label:                              'O'
+    base:                               '\u03bf'
+    shift, capslock:                    '\u039f'
+}
+
+key P {
+    label:                              'P'
+    base:                               '\u03c0'
+    shift, capslock:                    '\u03a0'
+}
+
+key LEFT_BRACKET {
+    label:                              '['
+    base, capslock:                     '['
+    shift:                              '{'
+    ralt:                               '\u00ab'
+}
+
+key RIGHT_BRACKET {
+    label:                              ']'
+    base, capslock:                     ']'
+    shift:                              '}'
+    ralt:                               '\u00bb'
+}
+
+### ROW 3
+
+key A {
+    label:                              'A'
+    base:                               '\u03b1'
+    shift, capslock:                    '\u0391'
+}
+
+key S {
+    label:                              'S'
+    base:                               '\u03c3'
+    shift, capslock:                    '\u03a3'
+}
+
+key D {
+    label:                              'D'
+    base:                               '\u03b4'
+    shift, capslock:                    '\u0394'
+}
+
+key F {
+    label:                              'F'
+    base:                               '\u03c6'
+    shift, capslock:                    '\u03a6'
+}
+
+key G {
+    label:                              'G'
+    base:                               '\u03b3'
+    shift, capslock:                    '\u0393'
+}
+
+key H {
+    label:                              'H'
+    base:                               '\u03b7'
+    shift, capslock:                    '\u0397'
+}
+
+key J {
+    label:                              'J'
+    base:                               '\u03be'
+    shift, capslock:                    '\u039e'
+}
+
+key K {
+    label:                              'K'
+    base:                               '\u03ba'
+    shift, capslock:                    '\u039a'
+}
+
+key L {
+    label:                              'L'
+    base:                               '\u03bb'
+    shift, capslock:                    '\u039b'
+}
+
+key SEMICOLON {
+    label:                              ';'
+    base, capslock:                     '\u0301'
+#should be \u0384 (greek tonos)
+    shift:                              '\u0308'
+    ralt:                               '\u0385'
+}
+
+key APOSTROPHE {
+    label:                              '\''
+    base, capslock:                     '\''
+    shift:                              '"'
+}
+
+key BACKSLASH {
+    label:                              '\\'
+    base, capslock:                     '\\'
+    shift:                              '|'
+    ralt:                               '\u00ac'
+}
+
+### ROW 4
+
+key PLUS {
+    label:                              '<'
+    base, capslock:                     '<'
+    shift:                              '>'
+    ralt:                               '\\'
+    shift+ralt:                         '|'
+}
+
+key Z {
+    label:                              'Z'
+    base:                               '\u03b6'
+    shift, capslock:                    '\u0396'
+}
+
+key X {
+    label:                              'X'
+    base:                               '\u03c7'
+    shift, capslock:                    '\u03a7'
+}
+
+key C {
+    label:                              'C'
+    base:                               '\u03c8'
+    shift, capslock:                    '\u03a8'
+    ralt:                               '\u00a9'
+}
+
+key V {
+    label:                              'V'
+    base:                               '\u03c9'
+    shift, capslock:                    '\u03a9'
+}
+
+key B {
+    label:                              'B'
+    base:                               '\u03b2'
+    shift, capslock:                    '\u0392'
+}
+
+key N {
+    label:                              'N'
+    base:                               '\u03bd'
+    shift, capslock:                    '\u039d'
+}
+
+key M {
+    label:                              'M'
+    base:                               '\u03bc'
+    shift, capslock:                    '\u039c'
+}
+
+key COMMA {
+    label:                              ','
+    base, capslock:                     ','
+    shift:                              '<'
+}
+
+key PERIOD {
+    label:                              '.'
+    base, capslock:                     '.'
+    shift:                              '>'
+}
+
+key SLASH {
+    label:                              '/'
+    base, capslock:                     '/'
+    shift:                              '?'
+}
diff --git a/packages/InputDevices/res/raw/keyboard_layout_hebrew.kcm b/packages/InputDevices/res/raw/keyboard_layout_hebrew.kcm
new file mode 100644
index 0000000..cd3a4b9
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_hebrew.kcm
@@ -0,0 +1,341 @@
+# 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.
+
+#
+# Hebrew (based EU) keyboard layout.
+#
+
+type OVERLAY
+
+map key 86 PLUS
+
+### ROW 1
+
+key GRAVE {
+    label:                              '`'
+    base:                               ';'
+    shift:                              '~'
+    shift+capslock:                     '\u05b0'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '1'
+    shift:                              '!'
+    shift+capslock:                     '\u05b1'
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '2'
+    shift:                              '@'
+    shift+capslock:                     '\u05b2'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '3'
+    shift:                              '#'
+    shift+capslock:                     '\u05b3'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '4'
+    shift:                              '$'
+    ralt:                               '\u20aa'
+    shift+capslock:                     '\u05b4'
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '5'
+    shift:                              '%'
+    shift+capslock:                     '\u05b5'
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '6'
+    shift:                              '^'
+    shift+capslock:                     '\u05b6'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '7'
+    shift:                              '&'
+    shift+capslock:                     '\u05b7'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '8'
+    shift:                              '*'
+    shift+capslock:                     '\u05b8'
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '9'
+    shift:                              '('
+    shift+capslock:                     '\u05c2'
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '0'
+    shift:                              ')'
+    shift+capslock:                     '\u05c1'
+}
+
+key MINUS {
+    label:                              '-'
+    base:                               '-'
+    shift:                              '_'
+    ralt:                               '\u05bf'
+    shift+capslock:                     '\u05b9'
+}
+
+key EQUALS {
+    label:                              '='
+    base:                               '='
+    shift:                              '+'
+    shift+capslock:                     '\u05bc'
+}
+
+### ROW 2
+
+key Q {
+    label:                              'Q'
+    base:                               '/'
+    shift, capslock:                    'Q'
+}
+
+key W {
+    label:                              'W'
+    base:                               '\u0027'
+    shift, capslock:                    'W'
+}
+
+key E {
+    label:                              'E'
+    base:                               '\u05e7'
+    shift, capslock:                    'E'
+    ralt:                               '\u20ac'
+}
+
+key R {
+    label:                              'R'
+    base:                               '\u05e8'
+    shift, capslock:                    'R'
+}
+
+key T {
+    label:                              'T'
+    base:                               '\u05d0'
+    shift, capslock:                    'T'
+}
+
+key Y {
+    label:                              'Y'
+    base:                               '\u05d8'
+    shift, capslock:                    'Y'
+}
+
+key U {
+    label:                              'U'
+    base:                               '\u05d5'
+    shift, capslock:                    'U'
+    ralt:                               '\u05f0'
+}
+
+key I {
+    label:                              'I'
+    base:                               '\u05df'
+    shift, capslock:                    'I'
+}
+
+key O {
+    label:                              'O'
+    base:                               '\u05dd'
+    shift, capslock:                    'O'
+}
+
+key P {
+    label:                              'P'
+    base:                               '\u05e4'
+    shift, capslock:                    'P'
+}
+
+key LEFT_BRACKET {
+    label:                              '['
+    base, capslock:                     '['
+    shift:                              '{'
+}
+
+key RIGHT_BRACKET {
+    label:                              ']'
+    base, capslock:                     ']'
+    shift:                              '}'
+}
+
+### ROW 3
+
+key A {
+    label:                              'A'
+    base:                               '\u05e9'
+    shift, capslock:                    'A'
+}
+
+key S {
+    label:                              'S'
+    base:                               '\u05d3'
+    shift, capslock:                    'S'
+}
+
+key D {
+    label:                              'D'
+    base:                               '\u05d2'
+    shift, capslock:                    'D'
+}
+
+key F {
+    label:                              'F'
+    base:                               '\u05db'
+    shift, capslock:                    'F'
+}
+
+key G {
+    label:                              'G'
+    base:                               '\u05e2'
+    shift, capslock:                    'G'
+}
+
+key H {
+    label:                              'H'
+    base:                               '\u05d9'
+    shift, capslock:                    'H'
+    ralt:                               '\u05f2'
+}
+
+key J {
+    label:                              'J'
+    base:                               '\u05d7'
+    shift, capslock:                    'J'
+    ralt:                               '\u05f1'
+}
+
+key K {
+    label:                              'K'
+    base:                               '\u05dc'
+    shift, capslock:                    'K'
+}
+
+key L {
+    label:                              'L'
+    base:                               '\u05da'
+    shift, capslock:                    'L'
+}
+
+key SEMICOLON {
+    label:                              ';'
+    base:                               '\u05e3'
+    shift:                              ':'
+    capslock:                           ';'
+}
+
+key APOSTROPHE {
+    label:                              '\''
+    base:                               ','
+    shift:                              '"'
+    capslock:                           '\''
+}
+
+key BACKSLASH {
+    label:                              '\\'
+    base:                               '\\'
+    shift:                              '|'
+}
+
+### ROW 4
+
+key PLUS {
+    label:                              '\\'
+    base, capslock:                     '\\'
+    shift:                              '|'
+}
+
+key Z {
+    label:                              'Z'
+    base:                               '\u05d6'
+    shift, capslock:                    'Z'
+}
+
+key X {
+    label:                              'X'
+    base:                               '\u05e1'
+    shift, capslock:                    'X'
+}
+
+key C {
+    label:                              'C'
+    base:                               '\u05d1'
+    shift, capslock:                    'C'
+}
+
+key V {
+    label:                              'V'
+    base:                               '\u05d4'
+    shift, capslock:                    'V'
+}
+
+key B {
+    label:                              'B'
+    base:                               '\u05e0'
+    shift, capslock:                    'B'
+}
+
+key N {
+    label:                              'N'
+    base:                               '\u05de'
+    shift, capslock:                    'N'
+}
+
+key M {
+    label:                              'M'
+    base:                               '\u05e6'
+    shift, capslock:                    'M'
+}
+
+key COMMA {
+    label:                              ','
+    base:                               '\u05ea'
+    shift:                              '<'
+    capslock:                           ','
+}
+
+key PERIOD {
+    label:                              '.'
+    base:                               '\u05e5'
+    shift:                              '>'
+    capslock:                           '.'
+}
+
+key SLASH {
+    label:                              '/'
+    base:                               '.'
+    shift:                              '?'
+    capslock:                           '/'
+}
diff --git a/packages/InputDevices/res/raw/keyboard_layout_lithuanian.kcm b/packages/InputDevices/res/raw/keyboard_layout_lithuanian.kcm
new file mode 100644
index 0000000..72ca333
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_lithuanian.kcm
@@ -0,0 +1,338 @@
+# 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.
+
+#
+# Lithuanian (EU based) keyboard layout.
+#
+
+type OVERLAY
+
+map key 86 PLUS
+
+### ROW 1
+
+key GRAVE {
+    label:                              '`'
+    base:                               '`'
+    shift:                              '~'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '\u0105'
+    shift, capslock:                    '\u0104'
+    ralt:                               '1'
+    shift+ralt:                         '!'
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '\u010d'
+    shift, capslock:                    '\u010c'
+    ralt:                               '2'
+    shift+ralt:                         '@'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '\u0119'
+    shift, capslock:                    '\u0118'
+    ralt:                               '3'
+    shift+ralt:                         '#'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '\u0117'
+    shift, capslock:                    '\u0116'
+    ralt:                               '4'
+    shift+ralt:                         '$'
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '\u012f'
+    shift, capslock:                    '\u012e'
+    ralt:                               '5'
+    shift+ralt:                         '%'
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '\u0161'
+    shift, capslock:                    '\u0160'
+    ralt:                               '6'
+    shift+ralt:                         '\u0302'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '\u0173'
+    shift, capslock:                    '\u0172'
+    ralt:                               '7'
+    shift+ralt:                         '&'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '\u016b'
+    shift, capslock:                    '\u016a'
+    ralt:                               '8'
+    shift+ralt:                         '*'
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '9'
+    shift:                              '('
+    ralt:                               '9'
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '0'
+    shift:                              ')'
+    ralt:                               '0'
+}
+
+key MINUS {
+    label:                              '-'
+    base:                               '-'
+    shift:                              '_'
+}
+
+key EQUALS {
+    label:                              '='
+    base:                               '\u017e'
+    shift, capslock:                    '\u017d'
+    ralt:                               '='
+    shift+ralt:                         '+'
+}
+
+### ROW 2
+
+key Q {
+    label:                              'Q'
+    base:                               'q'
+    shift, capslock:                    'Q'
+}
+
+key W {
+    label:                              'W'
+    base:                               'w'
+    shift, capslock:                    'W'
+}
+
+key E {
+    label:                              'E'
+    base:                               'e'
+    shift, capslock:                    'E'
+    ralt:                               '\u20ac'
+}
+
+key R {
+    label:                              'R'
+    base:                               'r'
+    shift, capslock:                    'R'
+}
+
+key T {
+    label:                              'T'
+    base:                               't'
+    shift, capslock:                    'T'
+}
+
+key Y {
+    label:                              'Y'
+    base:                               'y'
+    shift, capslock:                    'Y'
+}
+
+key U {
+    label:                              'U'
+    base:                               'u'
+    shift, capslock:                    'U'
+}
+
+key I {
+    label:                              'I'
+    base:                               'i'
+    shift, capslock:                    'I'
+}
+
+key O {
+    label:                              'O'
+    base:                               'o'
+    shift, capslock:                    'O'
+}
+
+key P {
+    label:                              'P'
+    base:                               'p'
+    shift, capslock:                    'P'
+}
+
+key LEFT_BRACKET {
+    label:                              '['
+    base:                               '['
+    shift:                              '{'
+}
+
+key RIGHT_BRACKET {
+    label:                              ']'
+    base:                               ']'
+    shift:                              '}'
+}
+
+### ROW 3
+
+key A {
+    label:                              'A'
+    base:                               'a'
+    shift, capslock:                    'A'
+}
+
+key S {
+    label:                              'S'
+    base:                               's'
+    shift, capslock:                    'S'
+}
+
+key D {
+    label:                              'D'
+    base:                               'd'
+    shift, capslock:                    'D'
+}
+
+key F {
+    label:                              'F'
+    base:                               'f'
+    shift, capslock:                    'F'
+}
+
+key G {
+    label:                              'G'
+    base:                               'g'
+    shift, capslock:                    'G'
+}
+
+key H {
+    label:                              'H'
+    base:                               'h'
+    shift, capslock:                    'H'
+}
+
+key J {
+    label:                              'J'
+    base:                               'j'
+    shift, capslock:                    'J'
+}
+
+key K {
+    label:                              'K'
+    base:                               'k'
+    shift, capslock:                    'K'
+}
+
+key L {
+    label:                              'L'
+    base:                               'l'
+    shift, capslock:                    'L'
+}
+
+key SEMICOLON {
+    label:                              ';'
+    base:                               ';'
+    shift:                              ':'
+}
+
+key APOSTROPHE {
+    label:                              '\''
+    base:                               '\''
+    shift:                              '"'
+}
+
+key BACKSLASH {
+    label:                              '\\'
+    base:                               '\\'
+    shift:                              '|'
+}
+
+### ROW 4
+
+key PLUS {
+    label:                              '\\'
+    base:                               '\\'
+    shift:                              '|'
+}
+
+key Z {
+    label:                              'Z'
+    base:                               'z'
+    shift, capslock:                    'Z'
+}
+
+key X {
+    label:                              'X'
+    base:                               'x'
+    shift, capslock:                    'X'
+}
+
+key C {
+    label:                              'C'
+    base:                               'c'
+    shift, capslock:                    'C'
+}
+
+key V {
+    label:                              'V'
+    base:                               'v'
+    shift, capslock:                    'V'
+}
+
+key B {
+    label:                              'B'
+    base:                               'b'
+    shift, capslock:                    'B'
+}
+
+key N {
+    label:                              'N'
+    base:                               'n'
+    shift, capslock:                    'N'
+}
+
+key M {
+    label:                              'M'
+    base:                               'm'
+    shift, capslock:                    'M'
+}
+
+key COMMA {
+    label:                              ','
+    base:                               ','
+    shift:                              '<'
+}
+
+key PERIOD {
+    label:                              '.'
+    base:                               '.'
+    shift:                              '>'
+}
+
+key SLASH {
+    label:                              '/'
+    base:                               '/'
+    shift:                              '?'
+}
diff --git a/packages/InputDevices/res/raw/keyboard_layout_spanish_latin.kcm b/packages/InputDevices/res/raw/keyboard_layout_spanish_latin.kcm
new file mode 100644
index 0000000..16eb53f
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_spanish_latin.kcm
@@ -0,0 +1,325 @@
+# 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.
+
+#
+# Spanish (Latin) (EU based) keyboard layout.
+#
+
+type OVERLAY
+
+map key 86 PLUS
+
+### ROW 1
+
+key GRAVE {
+    label:                              '|'
+    base:                               '|'
+    shift:                              '\u00ba'
+    ralt:                               '\u00ac'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '1'
+    shift:                              '!'
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '2'
+    shift:                              '"'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '3'
+    shift:                              '#'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '4'
+    shift:                              '$'
+
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '5'
+    shift:                              '%'
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '6'
+    shift:                              '&'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '7'
+    shift:                              '/'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '8'
+    shift:                              '('
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '9'
+    shift:                              ')'
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '0'
+    shift:                              '='
+}
+
+key MINUS {
+    label:                              '\''
+    base:                               '\''
+    shift:                              '?'
+    ralt:                               '\\'
+}
+
+key EQUALS {
+    label:                              '\u00bf'
+    base:                               '\u00bf'
+    shift:                              '\u00a1'
+}
+
+### ROW 2
+
+key Q {
+    label:                              'Q'
+    base:                               'q'
+    shift, capslock:                    'Q'
+    ralt:                               '@'
+}
+
+key W {
+    label:                              'W'
+    base:                               'w'
+    shift, capslock:                    'W'
+}
+
+key E {
+    label:                              'E'
+    base:                               'e'
+    shift, capslock:                    'E'
+}
+
+key R {
+    label:                              'R'
+    base:                               'r'
+    shift, capslock:                    'R'
+}
+
+key T {
+    label:                              'T'
+    base:                               't'
+    shift, capslock:                    'T'
+}
+
+key Y {
+    label:                              'Y'
+    base:                               'y'
+    shift, capslock:                    'Y'
+}
+
+key U {
+    label:                              'U'
+    base:                               'u'
+    shift, capslock:                    'U'
+}
+
+key I {
+    label:                              'I'
+    base:                               'i'
+    shift, capslock:                    'I'
+}
+
+key O {
+    label:                              'O'
+    base:                               'o'
+    shift, capslock:                    'O'
+}
+
+key P {
+    label:                              'P'
+    base:                               'p'
+    shift, capslock:                    'P'
+}
+
+key LEFT_BRACKET {
+    label:                              '\u00b4'
+    base:                               '\u0301'
+    shift:                              '\u0308'
+    ralt:                               '['
+}
+
+key RIGHT_BRACKET {
+    label:                              '+'
+    base:                               '+'
+    shift:                              '*'
+    ralt:                               '\u0303'
+}
+
+### ROW 3
+
+key A {
+    label:                              'A'
+    base:                               'a'
+    shift, capslock:                    'A'
+}
+
+key S {
+    label:                              'S'
+    base:                               's'
+    shift, capslock:                    'S'
+}
+
+key D {
+    label:                              'D'
+    base:                               'd'
+    shift, capslock:                    'D'
+}
+
+key F {
+    label:                              'F'
+    base:                               'f'
+    shift, capslock:                    'F'
+}
+
+key G {
+    label:                              'G'
+    base:                               'g'
+    shift, capslock:                    'G'
+}
+
+key H {
+    label:                              'H'
+    base:                               'h'
+    shift, capslock:                    'H'
+}
+
+key J {
+    label:                              'J'
+    base:                               'j'
+    shift, capslock:                    'J'
+}
+
+key K {
+    label:                              'K'
+    base:                               'k'
+    shift, capslock:                    'K'
+}
+
+key L {
+    label:                              'L'
+    base:                               'l'
+    shift, capslock:                    'L'
+}
+
+key SEMICOLON {
+    label:                              '\u00d1'
+    base:                               '\u00f1'
+    shift, capslock:                    '\u00d1'
+}
+
+key APOSTROPHE {
+    label:                              '{'
+    base:                               '{'
+    shift:                              '['
+    ralt:                               '\u0302'
+}
+
+key BACKSLASH {
+    label:                              '}'
+    base:                               '}'
+    shift:                              ']'
+    ralt:                               '\u0300'
+}
+
+### ROW 4
+
+key PLUS {
+    label:                              '<'
+    base:                               '<'
+    shift:                              '>'
+}
+
+key Z {
+    label:                              'Z'
+    base:                               'z'
+    shift, capslock:                    'Z'
+}
+
+key X {
+    label:                              'X'
+    base:                               'x'
+    shift, capslock:                    'X'
+}
+
+key C {
+    label:                              'C'
+    base:                               'c'
+    shift, capslock:                    'C'
+}
+
+key V {
+    label:                              'V'
+    base:                               'v'
+    shift, capslock:                    'V'
+}
+
+key B {
+    label:                              'B'
+    base:                               'b'
+    shift, capslock:                    'B'
+}
+
+key N {
+    label:                              'N'
+    base:                               'n'
+    shift, capslock:                    'N'
+}
+
+key M {
+    label:                              'M'
+    base:                               'm'
+    shift, capslock:                    'M'
+}
+
+key COMMA {
+    label:                              ','
+    base:                               ','
+    shift:                              ';'
+}
+
+key PERIOD {
+    label:                              '.'
+    base:                               '.'
+    shift:                              ':'
+}
+
+key SLASH {
+    label:                              '-'
+    base:                               '-'
+    shift:                              '_'
+}
diff --git a/packages/InputDevices/res/values-af/strings.xml b/packages/InputDevices/res/values-af/strings.xml
index 13fcbb4..ddaf706 100644
--- a/packages/InputDevices/res/values-af/strings.xml
+++ b/packages/InputDevices/res/values-af/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Sloweens"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turks"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Oekraïens"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabies"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grieks"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreeus"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litaus"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spaans (Latyn)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-am/strings.xml b/packages/InputDevices/res/values-am/strings.xml
index d475772..09b65e0 100644
--- a/packages/InputDevices/res/values-am/strings.xml
+++ b/packages/InputDevices/res/values-am/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"ስሎቫኒያ"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"ቱርክኛ"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ዩክሬን"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"አረብኛ"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"ግሪክኛ"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ዕብራስጥ"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"ሊቱዌኒያኛ"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ስፓኒሽ (ላቲን)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ar/strings.xml b/packages/InputDevices/res/values-ar/strings.xml
index 903d978..4c5cccc 100644
--- a/packages/InputDevices/res/values-ar/strings.xml
+++ b/packages/InputDevices/res/values-ar/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"السلوفينية"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"التركية"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"الأوكرانية"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"العربية"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"اليونانية"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"العبرية"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"الليتوانية"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"الإسبانية (اللاتينية)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-bg/strings.xml b/packages/InputDevices/res/values-bg/strings.xml
index 0c413a4..cc3eb36 100644
--- a/packages/InputDevices/res/values-bg/strings.xml
+++ b/packages/InputDevices/res/values-bg/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"словенски"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"турски"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"украински"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Арабска клавиатурна подредба"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Гръцка клавиатурна подредба"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ивритска клавиатурна подредба"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Литовска клавиатурна подредба"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Исп. клав. подредба (Лат. Америка)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ca/strings.xml b/packages/InputDevices/res/values-ca/strings.xml
index 2021b8f..2c8521c 100644
--- a/packages/InputDevices/res/values-ca/strings.xml
+++ b/packages/InputDevices/res/values-ca/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Eslovè"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turc"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraïnès"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Àrab"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grec"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreu"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituà"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espanyol (llatí)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-cs/strings.xml b/packages/InputDevices/res/values-cs/strings.xml
index 33b420e..9b65eed 100644
--- a/packages/InputDevices/res/values-cs/strings.xml
+++ b/packages/InputDevices/res/values-cs/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"slovinské"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"turecké"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrajinské"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arabština"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"řečtina"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebrejština"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litevština"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"španělština (Latinská Amerika)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-da/strings.xml b/packages/InputDevices/res/values-da/strings.xml
index fc07db2..8b157b4 100644
--- a/packages/InputDevices/res/values-da/strings.xml
+++ b/packages/InputDevices/res/values-da/strings.xml
@@ -34,4 +34,14 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovensk"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Tyrkisk"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainsk"</string>
+    <!-- no translation found for keyboard_layout_arabic (5671970465174968712) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_greek (7289253560162386040) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_hebrew (7241473985890173812) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_lithuanian (6943110873053106534) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_spanish_latin (5690539836069535697) -->
+    <skip />
 </resources>
diff --git a/packages/InputDevices/res/values-de/strings.xml b/packages/InputDevices/res/values-de/strings.xml
index b5c3b50..b5a5870 100644
--- a/packages/InputDevices/res/values-de/strings.xml
+++ b/packages/InputDevices/res/values-de/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slowenisch"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Türkisch"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainisch"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabisch"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Griechisch"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebräisch"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litauisch"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanisch (Lateinisch)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-el/strings.xml b/packages/InputDevices/res/values-el/strings.xml
index f5d57a0..976f370 100644
--- a/packages/InputDevices/res/values-el/strings.xml
+++ b/packages/InputDevices/res/values-el/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Σλοβενικά"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Τουρκικά"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ουκρανικά"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Αραβικά"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Ελληνικά"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Εβραϊκά"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Λιθουανικά"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Ισπανικά (Λατινικής Αμερικής)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-en-rGB/strings.xml b/packages/InputDevices/res/values-en-rGB/strings.xml
index 2d794a6..50a98b26 100644
--- a/packages/InputDevices/res/values-en-rGB/strings.xml
+++ b/packages/InputDevices/res/values-en-rGB/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenian"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turkish"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainian"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabic"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Greek"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrew"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lithuanian"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-en-rIN/strings.xml b/packages/InputDevices/res/values-en-rIN/strings.xml
index 2d794a6..50a98b26 100644
--- a/packages/InputDevices/res/values-en-rIN/strings.xml
+++ b/packages/InputDevices/res/values-en-rIN/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenian"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turkish"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainian"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabic"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Greek"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrew"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lithuanian"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-es-rUS/strings.xml b/packages/InputDevices/res/values-es-rUS/strings.xml
index 2d61b80..b842a3b 100644
--- a/packages/InputDevices/res/values-es-rUS/strings.xml
+++ b/packages/InputDevices/res/values-es-rUS/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Esloveno"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turco"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraniano"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Árabe"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Griego"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreo"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Español (latino)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-es/strings.xml b/packages/InputDevices/res/values-es/strings.xml
index 82ea4d6..8cb01c1 100644
--- a/packages/InputDevices/res/values-es/strings.xml
+++ b/packages/InputDevices/res/values-es/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Esloveno"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turco"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraniano"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Árabe"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Griego"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreo"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Español (latino)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-et-rEE/strings.xml b/packages/InputDevices/res/values-et-rEE/strings.xml
index 5b4fa3b..4ffdb37 100644
--- a/packages/InputDevices/res/values-et-rEE/strings.xml
+++ b/packages/InputDevices/res/values-et-rEE/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Sloveenia"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Türgi"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukraina"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Araabia"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Kreeka"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Heebrea"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Leedu"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Hispaania (Ladina-Ameerika)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-fa/strings.xml b/packages/InputDevices/res/values-fa/strings.xml
index 06c7f3a..fd6f54b 100644
--- a/packages/InputDevices/res/values-fa/strings.xml
+++ b/packages/InputDevices/res/values-fa/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"اسلوونیایی"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"ترکی"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"اوکراینی"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"عربی"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"یونانی"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"عبری"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"لیتوانیایی"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"اسپانیایی (لاتین)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-fi/strings.xml b/packages/InputDevices/res/values-fi/strings.xml
index 428eb30..7e9b386 100644
--- a/packages/InputDevices/res/values-fi/strings.xml
+++ b/packages/InputDevices/res/values-fi/strings.xml
@@ -34,4 +34,14 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"sloveeni"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"turkki"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukraina"</string>
+    <!-- no translation found for keyboard_layout_arabic (5671970465174968712) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_greek (7289253560162386040) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_hebrew (7241473985890173812) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_lithuanian (6943110873053106534) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_spanish_latin (5690539836069535697) -->
+    <skip />
 </resources>
diff --git a/packages/InputDevices/res/values-fr-rCA/strings.xml b/packages/InputDevices/res/values-fr-rCA/strings.xml
index c947634..9000405 100644
--- a/packages/InputDevices/res/values-fr-rCA/strings.xml
+++ b/packages/InputDevices/res/values-fr-rCA/strings.xml
@@ -34,4 +34,14 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovène"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turc"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainien"</string>
+    <!-- no translation found for keyboard_layout_arabic (5671970465174968712) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_greek (7289253560162386040) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_hebrew (7241473985890173812) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_lithuanian (6943110873053106534) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_spanish_latin (5690539836069535697) -->
+    <skip />
 </resources>
diff --git a/packages/InputDevices/res/values-fr/strings.xml b/packages/InputDevices/res/values-fr/strings.xml
index 4ad4ffa..e3ca49c 100644
--- a/packages/InputDevices/res/values-fr/strings.xml
+++ b/packages/InputDevices/res/values-fr/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovène"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turc"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainien"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabe"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grec"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hébreu"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituanien"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espagnol (latin)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-hi/strings.xml b/packages/InputDevices/res/values-hi/strings.xml
index 8e1864e..a1a4ef2 100644
--- a/packages/InputDevices/res/values-hi/strings.xml
+++ b/packages/InputDevices/res/values-hi/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"स्लोवेनियाई"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"तुर्की"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"यूक्रेनियाई"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"अरबी"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"ग्रीक"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"हिब्रू"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"लिथुआनियाई"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"स्पेनिश (लैटिन)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-hr/strings.xml b/packages/InputDevices/res/values-hr/strings.xml
index 6217bf0..0f83293 100644
--- a/packages/InputDevices/res/values-hr/strings.xml
+++ b/packages/InputDevices/res/values-hr/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"slovenska"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"turska"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrajinska"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arapski"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grčki"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrejski"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litavski"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Španjolski (Latinska Amerika)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-hu/strings.xml b/packages/InputDevices/res/values-hu/strings.xml
index 0cdbfb2..645e597 100644
--- a/packages/InputDevices/res/values-hu/strings.xml
+++ b/packages/InputDevices/res/values-hu/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"szlovén"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"török"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrán"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arab"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"görög"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"héber"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litván"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"spanyol (latin-amerikai)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-hy-rAM/strings.xml b/packages/InputDevices/res/values-hy-rAM/strings.xml
index bc5bbfc..282dc82 100644
--- a/packages/InputDevices/res/values-hy-rAM/strings.xml
+++ b/packages/InputDevices/res/values-hy-rAM/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Սլովեներեն"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Թուրքերեն"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ուկրաիներեն"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Արաբերեն"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Հունարեն"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Եբրայերեն"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Լիտվերեն"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Իսպաներեն (Լատինական)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-in/strings.xml b/packages/InputDevices/res/values-in/strings.xml
index 11e2dd0a..a7fc330 100644
--- a/packages/InputDevices/res/values-in/strings.xml
+++ b/packages/InputDevices/res/values-in/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenia"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turki"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukraina"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arab"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Yunani"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ibrani"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lithuania"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanyol (Latin)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-it/strings.xml b/packages/InputDevices/res/values-it/strings.xml
index 334318e..e8fe310 100644
--- a/packages/InputDevices/res/values-it/strings.xml
+++ b/packages/InputDevices/res/values-it/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Sloveno"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turco"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraino"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabo"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Greco"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ebraico"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spagnolo (America Latina)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-iw/strings.xml b/packages/InputDevices/res/values-iw/strings.xml
index a989391..d2673d9 100644
--- a/packages/InputDevices/res/values-iw/strings.xml
+++ b/packages/InputDevices/res/values-iw/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"סלובנית"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"טורקית"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"אוקראינית"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"ערבית"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"יוונית"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"עברית"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"ליטאית"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ספרדית (לטינית)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ja/strings.xml b/packages/InputDevices/res/values-ja/strings.xml
index 950b727..86cd30e 100644
--- a/packages/InputDevices/res/values-ja/strings.xml
+++ b/packages/InputDevices/res/values-ja/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"スロベニア語"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"トルコ語"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ウクライナ語"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"アラビア語"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"ギリシャ語"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ヘブライ語"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"リトアニア語"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"スペイン語(中南米)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ka-rGE/strings.xml b/packages/InputDevices/res/values-ka-rGE/strings.xml
index 6e507aa..14ebee8 100644
--- a/packages/InputDevices/res/values-ka-rGE/strings.xml
+++ b/packages/InputDevices/res/values-ka-rGE/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"სლოვენური"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"თურქული"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"უკრაინული"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"არაბული"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"ბერძნული"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ებრაული"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"ლიტვური"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ესპანური (ლათინური)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-km-rKH/strings.xml b/packages/InputDevices/res/values-km-rKH/strings.xml
index 9a8c99b..569f273 100644
--- a/packages/InputDevices/res/values-km-rKH/strings.xml
+++ b/packages/InputDevices/res/values-km-rKH/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"ស្លូវ៉ានី"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"ទួរគី"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"អ៊ុយក្រែន"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"អារ៉ាប់"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"ក្រិក"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"អ៊ីស្រាអែល"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"លីទុយអានី"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"អេស្ប៉ាញ (ឡាតាំង​)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ko/strings.xml b/packages/InputDevices/res/values-ko/strings.xml
index 8071586..dbbe6ea 100644
--- a/packages/InputDevices/res/values-ko/strings.xml
+++ b/packages/InputDevices/res/values-ko/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"슬로베니아어"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"터키어"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"우크라이나어"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"아랍어"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"그리스어"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"히브리어"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"리투아니아어"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"스페인어(라틴)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-lo-rLA/strings.xml b/packages/InputDevices/res/values-lo-rLA/strings.xml
index 2c97e11..eaf5026 100644
--- a/packages/InputDevices/res/values-lo-rLA/strings.xml
+++ b/packages/InputDevices/res/values-lo-rLA/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"ສະໂລເວນຽນ"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"ເຕີກິສ"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ຢູເຄຣນຽນ"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"ອາຣັບ"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"ກ​ຣີກ"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ຮີບຣິວ"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"​ລິ​ທົວ​ນຽນ"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"​ສະ​ແປນ​ນິດ (ລາ​ຕິນ)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-lt/strings.xml b/packages/InputDevices/res/values-lt/strings.xml
index c0ed159..2fcacde 100644
--- a/packages/InputDevices/res/values-lt/strings.xml
+++ b/packages/InputDevices/res/values-lt/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovėnų k."</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turkų k."</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainiečių k."</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabų"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Graikų"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrajų"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lietuvių"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Ispanų (Lotynų Amerika)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-lv/strings.xml b/packages/InputDevices/res/values-lv/strings.xml
index 07a8654..921c881 100644
--- a/packages/InputDevices/res/values-lv/strings.xml
+++ b/packages/InputDevices/res/values-lv/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovēņu"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turku"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukraiņu"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arābu"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grieķu"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ivrits"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lietuviešu"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spāņu (latīņu)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-mn-rMN/strings.xml b/packages/InputDevices/res/values-mn-rMN/strings.xml
index ec6cccb..c99339e 100644
--- a/packages/InputDevices/res/values-mn-rMN/strings.xml
+++ b/packages/InputDevices/res/values-mn-rMN/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Словени"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Турк"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Украйн"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Араб"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Грек"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Еврей"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Литви"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Испани (Латин)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ms-rMY/strings.xml b/packages/InputDevices/res/values-ms-rMY/strings.xml
index 486f048..b26a633 100644
--- a/packages/InputDevices/res/values-ms-rMY/strings.xml
+++ b/packages/InputDevices/res/values-ms-rMY/strings.xml
@@ -34,4 +34,14 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Bahasa Slovenia"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Bahasa Turki"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Bahasa Ukraine"</string>
+    <!-- no translation found for keyboard_layout_arabic (5671970465174968712) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_greek (7289253560162386040) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_hebrew (7241473985890173812) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_lithuanian (6943110873053106534) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_spanish_latin (5690539836069535697) -->
+    <skip />
 </resources>
diff --git a/packages/InputDevices/res/values-nb/strings.xml b/packages/InputDevices/res/values-nb/strings.xml
index b646061..e880981 100644
--- a/packages/InputDevices/res/values-nb/strings.xml
+++ b/packages/InputDevices/res/values-nb/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovensk"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Tyrkisk"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainsk"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabisk"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Gresk"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebraisk"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litauisk"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spansk (latinsk)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-nl/strings.xml b/packages/InputDevices/res/values-nl/strings.xml
index 56d84c9..92a9fcf 100644
--- a/packages/InputDevices/res/values-nl/strings.xml
+++ b/packages/InputDevices/res/values-nl/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Sloveens"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turks"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Oekraïens"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabisch"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grieks"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreeuws"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litouws"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spaans (Latijns-Amerika)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-pl/strings.xml b/packages/InputDevices/res/values-pl/strings.xml
index 4522215..828a45f 100644
--- a/packages/InputDevices/res/values-pl/strings.xml
+++ b/packages/InputDevices/res/values-pl/strings.xml
@@ -34,4 +34,14 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Słoweński"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turecki"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukraiński"</string>
+    <!-- no translation found for keyboard_layout_arabic (5671970465174968712) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_greek (7289253560162386040) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_hebrew (7241473985890173812) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_lithuanian (6943110873053106534) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_spanish_latin (5690539836069535697) -->
+    <skip />
 </resources>
diff --git a/packages/InputDevices/res/values-pt-rPT/strings.xml b/packages/InputDevices/res/values-pt-rPT/strings.xml
index 9a639cd..670badd 100644
--- a/packages/InputDevices/res/values-pt-rPT/strings.xml
+++ b/packages/InputDevices/res/values-pt-rPT/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Esloveno"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turco"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraniano"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Árabe"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grego"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebraico"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espanhol (América Latina)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-pt/strings.xml b/packages/InputDevices/res/values-pt/strings.xml
index 05a0cd0..71274aa 100644
--- a/packages/InputDevices/res/values-pt/strings.xml
+++ b/packages/InputDevices/res/values-pt/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Esloveno"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turco"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraniano"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Árabe"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grego"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebraico"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espanhol (América Latina)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ro/strings.xml b/packages/InputDevices/res/values-ro/strings.xml
index 895d8f6..c61455d 100644
--- a/packages/InputDevices/res/values-ro/strings.xml
+++ b/packages/InputDevices/res/values-ro/strings.xml
@@ -34,4 +34,14 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenă"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turcă"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraineană"</string>
+    <!-- no translation found for keyboard_layout_arabic (5671970465174968712) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_greek (7289253560162386040) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_hebrew (7241473985890173812) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_lithuanian (6943110873053106534) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_spanish_latin (5690539836069535697) -->
+    <skip />
 </resources>
diff --git a/packages/InputDevices/res/values-ru/strings.xml b/packages/InputDevices/res/values-ru/strings.xml
index a4cbfd7..8b93723 100644
--- a/packages/InputDevices/res/values-ru/strings.xml
+++ b/packages/InputDevices/res/values-ru/strings.xml
@@ -34,4 +34,14 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"словенский"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"турецкий"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"украинский"</string>
+    <!-- no translation found for keyboard_layout_arabic (5671970465174968712) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_greek (7289253560162386040) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_hebrew (7241473985890173812) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_lithuanian (6943110873053106534) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_spanish_latin (5690539836069535697) -->
+    <skip />
 </resources>
diff --git a/packages/InputDevices/res/values-sk/strings.xml b/packages/InputDevices/res/values-sk/strings.xml
index 01ab042..ec511b3 100644
--- a/packages/InputDevices/res/values-sk/strings.xml
+++ b/packages/InputDevices/res/values-sk/strings.xml
@@ -34,4 +34,14 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"slovinské"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"turecké"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrajinské"</string>
+    <!-- no translation found for keyboard_layout_arabic (5671970465174968712) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_greek (7289253560162386040) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_hebrew (7241473985890173812) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_lithuanian (6943110873053106534) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_spanish_latin (5690539836069535697) -->
+    <skip />
 </resources>
diff --git a/packages/InputDevices/res/values-sl/strings.xml b/packages/InputDevices/res/values-sl/strings.xml
index 30ff3c4..b8fc823e 100644
--- a/packages/InputDevices/res/values-sl/strings.xml
+++ b/packages/InputDevices/res/values-sl/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"slovenska"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"turška"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrajinska"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arabščina"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"grščina"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebrejščina"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litovščina"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"španščina (Latinska Amerika)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-sr/strings.xml b/packages/InputDevices/res/values-sr/strings.xml
index d23ac00..45e0b4b 100644
--- a/packages/InputDevices/res/values-sr/strings.xml
+++ b/packages/InputDevices/res/values-sr/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"словеначка"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"турска"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"украјинска"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"арапски"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"грчки"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"хебрејски"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"литвански"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"шпански (Латинска Америка)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-sv/strings.xml b/packages/InputDevices/res/values-sv/strings.xml
index 25a5ae8..ce20bff 100644
--- a/packages/InputDevices/res/values-sv/strings.xml
+++ b/packages/InputDevices/res/values-sv/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenskt"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turkiskt"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainskt"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabiska"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grekiska"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreiska"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litauiska"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanska (latinamerikansk)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-sw/strings.xml b/packages/InputDevices/res/values-sw/strings.xml
index 65ab96a1..38bc83a 100644
--- a/packages/InputDevices/res/values-sw/strings.xml
+++ b/packages/InputDevices/res/values-sw/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Kislovenia"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Kituruki"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Kiukrania"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Kiarabu"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Kigiriki"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Kiyahudi"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Kilithuania"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Kihispania (Kilatini)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-th/strings.xml b/packages/InputDevices/res/values-th/strings.xml
index 0cc7d47..8951281 100644
--- a/packages/InputDevices/res/values-th/strings.xml
+++ b/packages/InputDevices/res/values-th/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"สโลวีเนีย"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"ตุรกี"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ยูเครน"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"ภาษาอารบิค"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"กรีก"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ฮิบรู"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"ลิทัวเนีย"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"สเปน (ละติน)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-tl/strings.xml b/packages/InputDevices/res/values-tl/strings.xml
index 08f34d2..c551e20 100644
--- a/packages/InputDevices/res/values-tl/strings.xml
+++ b/packages/InputDevices/res/values-tl/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenian"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turkish"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainian"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabic"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Greek"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrew"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lithuanian"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-tr/strings.xml b/packages/InputDevices/res/values-tr/strings.xml
index f7c1262..df9a280 100644
--- a/packages/InputDevices/res/values-tr/strings.xml
+++ b/packages/InputDevices/res/values-tr/strings.xml
@@ -34,4 +34,14 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovence"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Türkçe"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukraynaca"</string>
+    <!-- no translation found for keyboard_layout_arabic (5671970465174968712) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_greek (7289253560162386040) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_hebrew (7241473985890173812) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_lithuanian (6943110873053106534) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_spanish_latin (5690539836069535697) -->
+    <skip />
 </resources>
diff --git a/packages/InputDevices/res/values-uk/strings.xml b/packages/InputDevices/res/values-uk/strings.xml
index ee6ffc7..b4b9923 100644
--- a/packages/InputDevices/res/values-uk/strings.xml
+++ b/packages/InputDevices/res/values-uk/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"словенська"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"турецька"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"українська"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Арабська"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Грецька"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Іврит"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Литовська"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Іспанська (латиниця)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-vi/strings.xml b/packages/InputDevices/res/values-vi/strings.xml
index 7a65e45..18aa989 100644
--- a/packages/InputDevices/res/values-vi/strings.xml
+++ b/packages/InputDevices/res/values-vi/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Tiếng Sloven"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Tiếng Thổ Nhĩ Kỳ"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Tiếng Ukraina"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Tiếng Ả rập"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Tiếng Hy Lạp"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Tiếng Do Thái"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Tiếng Lithuania"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Tiếng Tây Ban Nha (La tinh)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-zh-rCN/strings.xml b/packages/InputDevices/res/values-zh-rCN/strings.xml
index 85b1c84..e055ce2 100644
--- a/packages/InputDevices/res/values-zh-rCN/strings.xml
+++ b/packages/InputDevices/res/values-zh-rCN/strings.xml
@@ -34,4 +34,14 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"斯洛文尼亚语"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"土耳其语"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"乌克兰语"</string>
+    <!-- no translation found for keyboard_layout_arabic (5671970465174968712) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_greek (7289253560162386040) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_hebrew (7241473985890173812) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_lithuanian (6943110873053106534) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_spanish_latin (5690539836069535697) -->
+    <skip />
 </resources>
diff --git a/packages/InputDevices/res/values-zh-rHK/strings.xml b/packages/InputDevices/res/values-zh-rHK/strings.xml
index 839c546..031f294 100644
--- a/packages/InputDevices/res/values-zh-rHK/strings.xml
+++ b/packages/InputDevices/res/values-zh-rHK/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"斯洛文尼亞文"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"土耳其文"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"烏克蘭文"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"阿拉伯文"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"希臘文"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"希伯來文"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"立陶宛文"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"西班牙文 (拉丁美洲)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-zh-rTW/strings.xml b/packages/InputDevices/res/values-zh-rTW/strings.xml
index ba9f132..76cb6a2 100644
--- a/packages/InputDevices/res/values-zh-rTW/strings.xml
+++ b/packages/InputDevices/res/values-zh-rTW/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"斯洛維尼亞文"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"土耳其文"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"烏克蘭文"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"阿拉伯文"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"希臘文"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"希伯來文"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"立陶宛文"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"西班牙文 (拉丁美洲)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-zu/strings.xml b/packages/InputDevices/res/values-zu/strings.xml
index fbf1074..2cdfe52 100644
--- a/packages/InputDevices/res/values-zu/strings.xml
+++ b/packages/InputDevices/res/values-zu/strings.xml
@@ -34,4 +34,9 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Isi-Slovenian"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Isi-Turkish"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Isi-Ukrainian"</string>
+    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"I-Arabhu"</string>
+    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Isi-Greek"</string>
+    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Isi-Hebrew"</string>
+    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Isi-Lithuanian"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Isi-Spanish (Latin)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values/strings.xml b/packages/InputDevices/res/values/strings.xml
index 54c18f1..6239336 100644
--- a/packages/InputDevices/res/values/strings.xml
+++ b/packages/InputDevices/res/values/strings.xml
@@ -98,4 +98,19 @@
 
     <!-- Ukrainian keyboard layout label. [CHAR LIMIT=35] -->
     <string name="keyboard_layout_ukrainian">Ukrainian</string>
+
+    <!-- Arabic keyboard layout label. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_arabic">Arabic</string>
+
+    <!-- Greek keyboard layout label. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_greek">Greek</string>
+
+    <!-- Hebrew keyboard layout label. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_hebrew">Hebrew</string>
+
+    <!-- Lithuanian keyboard layout label. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_lithuanian">Lithuanian</string>
+
+    <!-- Spanish (Latin) keyboard layout label. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_spanish_latin">Spanish (Latin)</string>
 </resources>
diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml
index 1f48a36..dc1db0b 100644
--- a/packages/InputDevices/res/xml/keyboard_layouts.xml
+++ b/packages/InputDevices/res/xml/keyboard_layouts.xml
@@ -123,4 +123,24 @@
     <keyboard-layout android:name="keyboard_layout_ukrainian"
             android:label="@string/keyboard_layout_ukrainian"
             android:keyboardLayout="@raw/keyboard_layout_ukrainian" />
+
+    <keyboard-layout android:name="keyboard_layout_arabic"
+            android:label="@string/keyboard_layout_arabic"
+            android:keyboardLayout="@raw/keyboard_layout_arabic" />
+
+    <keyboard-layout android:name="keyboard_layout_greek"
+            android:label="@string/keyboard_layout_greek"
+            android:keyboardLayout="@raw/keyboard_layout_greek" />
+
+    <keyboard-layout android:name="keyboard_layout_hebrew"
+            android:label="@string/keyboard_layout_hebrew"
+            android:keyboardLayout="@raw/keyboard_layout_hebrew" />
+
+    <keyboard-layout android:name="keyboard_layout_lithuanian"
+            android:label="@string/keyboard_layout_lithuanian"
+            android:keyboardLayout="@raw/keyboard_layout_lithuanian" />
+
+    <keyboard-layout android:name="keyboard_layout_spanish_latin"
+            android:label="@string/keyboard_layout_spanish_latin"
+            android:keyboardLayout="@raw/keyboard_layout_spanish_latin" />
 </keyboard-layouts>
diff --git a/packages/Keyguard/AndroidManifest.xml b/packages/Keyguard/AndroidManifest.xml
index 66d1e75..75b7dbd 100644
--- a/packages/Keyguard/AndroidManifest.xml
+++ b/packages/Keyguard/AndroidManifest.xml
@@ -39,11 +39,13 @@
     <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
     <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
     <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
+    <uses-permission android:name="android.permission.TRUST_LISTENER" />
 
     <application android:label="@string/app_name"
         android:process="com.android.systemui"
         android:persistent="true"
-        android:supportsRtl="true">
+        android:supportsRtl="true"
+        android:requiredForProfile="all">
 
         <service android:name=".KeyguardService"
             android:exported="true" />
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java b/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java
index 368a97a..0d5e477 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java
@@ -104,9 +104,10 @@
 
         // Workaround to avoid camera release/acquisition race when resuming face unlock
         // after showing lockscreen camera (bug 11063890).
-        KeyguardUpdateMonitor.getInstance(getContext()).setAlternateUnlockEnabled(false);
+        KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(getContext());
+        updateMonitor.setAlternateUnlockEnabled(false);
 
-        if (lockPatternUtils.isSecure()) {
+        if (mustLaunchSecurely()) {
             // Launch the secure version of the camera
             if (wouldLaunchResolverActivity(SECURE_CAMERA_INTENT)) {
                 // TODO: Show disambiguation dialog instead.
@@ -123,6 +124,13 @@
         }
     }
 
+    private boolean mustLaunchSecurely() {
+        LockPatternUtils lockPatternUtils = getLockPatternUtils();
+        KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(getContext());
+        int currentUser = lockPatternUtils.getCurrentUser();
+        return lockPatternUtils.isSecure() && !updateMonitor.getUserHasTrust(currentUser);
+    }
+
     public void launchWidgetPicker(int appWidgetId) {
         Intent pickIntent = new Intent(AppWidgetManager.ACTION_KEYGUARD_APPWIDGET_PICK);
 
@@ -177,9 +185,9 @@
                 Intent.FLAG_ACTIVITY_NEW_TASK
                 | Intent.FLAG_ACTIVITY_SINGLE_TOP
                 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        boolean isSecure = lockPatternUtils.isSecure();
-        if (!isSecure || showsWhileLocked) {
-            if (!isSecure) {
+        boolean mustLaunchSecurely = mustLaunchSecurely();
+        if (!mustLaunchSecurely || showsWhileLocked) {
+            if (!mustLaunchSecurely) {
                 dismissKeyguardOnNextActivity();
             }
             try {
@@ -253,7 +261,7 @@
     }
 
     private Intent getCameraIntent() {
-        return getLockPatternUtils().isSecure() ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
+        return mustLaunchSecurely() ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
     }
 
     private boolean wouldLaunchResolverActivity(Intent intent) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
index 9f5768a..da6482a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -23,6 +23,7 @@
 import com.android.internal.widget.LockPatternUtils;
 
 public class KeyguardSecurityModel {
+
     /**
      * The different types of security available for {@link Mode#UnlockScreen}.
      * @see com.android.internal.policy.impl.LockPatternKeyguardView#getUnlockMode()
@@ -82,6 +83,8 @@
         } else if (simState == IccCardConstants.State.PUK_REQUIRED
                 && mLockPatternUtils.isPukUnlockScreenEnable()) {
             mode = SecurityMode.SimPuk;
+        } else if (updateMonitor.getUserHasTrust(mLockPatternUtils.getCurrentUser())) {
+            mode = SecurityMode.None;
         } else {
             final int security = mLockPatternUtils.getKeyguardStoredPasswordQuality();
             switch (security) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 3b712e9..88c78ab 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -20,6 +20,7 @@
 import android.app.IUserSwitchObserver;
 import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
+import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -51,6 +52,8 @@
 
 import android.telephony.TelephonyManager;
 import android.util.Log;
+import android.util.SparseBooleanArray;
+
 import com.google.android.collect.Lists;
 
 import java.lang.ref.WeakReference;
@@ -66,7 +69,7 @@
  * the device, and {@link #getFailedUnlockAttempts()}, {@link #reportFailedAttempt()}
  * and {@link #clearFailedUnlockAttempts()}.  Maybe we should rename this 'KeyguardContext'...
  */
-public class KeyguardUpdateMonitor {
+public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
 
     private static final String TAG = "KeyguardUpdateMonitor";
     private static final boolean DEBUG = false;
@@ -205,6 +208,17 @@
 
     private AudioManager mAudioManager;
 
+    private SparseBooleanArray mUserHasTrust = new SparseBooleanArray();
+
+    @Override
+    public void onTrustChanged(boolean enabled, int userId) {
+        mUserHasTrust.put(userId, enabled);
+    }
+
+    public boolean getUserHasTrust(int userId) {
+        return mUserHasTrust.get(userId);
+    }
+
     static class DisplayClientState {
         public int clientGeneration;
         public boolean clearing;
@@ -581,6 +595,9 @@
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
+
+        TrustManager trustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE);
+        trustManager.registerTrustListener(this);
     }
 
     private boolean isDeviceProvisionedInSettingsDb() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 481d132..556711b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -178,4 +178,5 @@
      * Called when the NFC Service has found a tag that is registered for NFC unlock.
      */
     public void onNfcUnlock() { }
+
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
index 31e806c..354d13f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
@@ -550,7 +550,9 @@
 
                 @Override
                 public int getSessionType() {
-                    return mLockPatternUtils.isSecure() ? Session.TYPE_KEYGUARD_SECURE
+                    return mLockPatternUtils.isSecure() && !mUpdateMonitor.getUserHasTrust(
+                            mLockPatternUtils.getCurrentUser())
+                            ? Session.TYPE_KEYGUARD_SECURE
                             : Session.TYPE_KEYGUARD_INSECURE;
                 }
             }, new File(mContext.getCacheDir(), "keyguard_analytics.bin"));
@@ -979,6 +981,13 @@
             return;
         }
 
+        if (mLockPatternUtils.checkVoldPassword()) {
+            if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
+            // Without this, settings is not enabled until the lock screen first appears
+            hideLocked();
+            return;
+        }
+
         if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
         showLocked(options);
     }
diff --git a/packages/Keyguard/test/SampleTrustAgent/Android.mk b/packages/Keyguard/test/SampleTrustAgent/Android.mk
new file mode 100644
index 0000000..7551fdf
--- /dev/null
+++ b/packages/Keyguard/test/SampleTrustAgent/Android.mk
@@ -0,0 +1,33 @@
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := SampleTrustAgent
+
+# Remove these to verify permission checks are working correctly
+#LOCAL_CERTIFICATE := platform
+#LOCAL_PRIVILEGED_MODULE := true
+
+LOCAL_MODULE_TAGS := tests
+
+# LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+
+include $(BUILD_PACKAGE)
diff --git a/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml b/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml
new file mode 100644
index 0000000..1511911
--- /dev/null
+++ b/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.trustagent.test">
+    <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="17"/>
+    <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
+    <application android:label="@string/app_name">
+      <service
+          android:name=".SampleTrustAgent"
+          android:label="@string/app_name"
+          android:exported="true">
+        <intent-filter>
+          <action android:name="android.service.trust.TrustAgentService" />
+          <category android:name="android.intent.category.DEFAULT" />
+        </intent-filter>
+        <meta-data android:name="android.service.trust.trustagent"
+                   android:resource="@xml/sample_trust_agent"/>
+      </service>
+
+      <activity
+          android:name=".SampleTrustAgentSettings"
+          android:label="@string/app_name"
+          android:exported="true"
+          android:launchMode="singleInstance" >
+      </activity>
+    </application>
+</manifest>
diff --git a/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml b/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml
new file mode 100644
index 0000000..01b107b
--- /dev/null
+++ b/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+    <Button android:id="@+id/enable_trust"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="Grant trust for 30 seconds" />
+    <Button android:id="@+id/revoke_trust"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="Revoke trust" />
+    <CheckBox android:id="@+id/report_unlock_attempts"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="Report unlock attempts" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/Keyguard/test/SampleTrustAgent/res/values/strings.xml b/packages/Keyguard/test/SampleTrustAgent/res/values/strings.xml
new file mode 100644
index 0000000..0c6b502
--- /dev/null
+++ b/packages/Keyguard/test/SampleTrustAgent/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+    <string name="app_name">Sample Trust Agent</string>
+</resources>
\ No newline at end of file
diff --git a/packages/Keyguard/test/SampleTrustAgent/res/xml/sample_trust_agent.xml b/packages/Keyguard/test/SampleTrustAgent/res/xml/sample_trust_agent.xml
new file mode 100644
index 0000000..b48e011
--- /dev/null
+++ b/packages/Keyguard/test/SampleTrustAgent/res/xml/sample_trust_agent.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<trust_agent xmlns:android="http://schemas.android.com/apk/res/android"
+        android:settingsActivity=".SampleTrustAgentSettings" />
diff --git a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
new file mode 100644
index 0000000..25406d6
--- /dev/null
+++ b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
@@ -0,0 +1,107 @@
+/*
+ * 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.trustagent.test;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.service.trust.TrustAgentService;
+import android.support.v4.content.LocalBroadcastManager;
+import android.widget.Toast;
+
+public class SampleTrustAgent extends TrustAgentService {
+
+    LocalBroadcastManager mLocalBroadcastManager;
+
+    private static final String ACTION_ENABLE_TRUST = "action.sample_trust_agent.enable_trust";
+    private static final String ACTION_REVOKE_TRUST = "action.sample_trust_agent.revoke_trust";
+
+    private static final String EXTRA_MESSAGE = "extra.message";
+    private static final String EXTRA_DURATION = "extra.duration";
+    private static final String EXTRA_EXTRA = "extra.extra";
+
+    private static final String PREFERENCE_REPORT_UNLOCK_ATTEMPTS
+            = "preference.report_unlock_attempts";
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_ENABLE_TRUST);
+        filter.addAction(ACTION_REVOKE_TRUST);
+        mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
+        mLocalBroadcastManager.registerReceiver(mReceiver, filter);
+    }
+
+    @Override
+    protected void onUnlockAttempt(boolean successful) {
+        if (getReportUnlockAttempts(this)) {
+            Toast.makeText(this, "onUnlockAttempt(successful=" + successful + ")",
+                    Toast.LENGTH_SHORT).show();
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        mLocalBroadcastManager.unregisterReceiver(mReceiver);
+    }
+
+    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (ACTION_ENABLE_TRUST.equals(action)) {
+                enableTrust(intent.getStringExtra(EXTRA_MESSAGE),
+                        intent.getLongExtra(EXTRA_DURATION, 0),
+                        false /* initiatedByUser */);
+            } else if (ACTION_REVOKE_TRUST.equals(action)) {
+                revokeTrust();
+            }
+        }
+    };
+
+    public static void sendEnableTrust(Context context,
+            String message, long durationMs, Bundle extra) {
+        Intent intent = new Intent(ACTION_ENABLE_TRUST);
+        intent.putExtra(EXTRA_MESSAGE, message);
+        intent.putExtra(EXTRA_DURATION, durationMs);
+        intent.putExtra(EXTRA_EXTRA, extra);
+        LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
+    }
+
+    public static void sendRevokeTrust(Context context) {
+        Intent intent = new Intent(ACTION_REVOKE_TRUST);
+        LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
+    }
+
+    public static void setReportUnlockAttempts(Context context, boolean enabled) {
+        SharedPreferences sharedPreferences = PreferenceManager
+                .getDefaultSharedPreferences(context);
+        sharedPreferences.edit().putBoolean(PREFERENCE_REPORT_UNLOCK_ATTEMPTS, enabled).apply();
+    }
+
+    public static boolean getReportUnlockAttempts(Context context) {
+        SharedPreferences sharedPreferences = PreferenceManager
+                .getDefaultSharedPreferences(context);
+        return sharedPreferences.getBoolean(PREFERENCE_REPORT_UNLOCK_ATTEMPTS, false);
+    }
+}
diff --git a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
new file mode 100644
index 0000000..0a6f675
--- /dev/null
+++ b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.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.trustagent.test;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.os.Bundle;
+import android.preference.CheckBoxPreference;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+
+public class SampleTrustAgentSettings extends Activity implements View.OnClickListener,
+        CompoundButton.OnCheckedChangeListener {
+
+    private static final int TRUST_DURATION_MS = 30 * 1000;
+
+    private CheckBox mReportUnlockAttempts;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.sample_trust_agent_settings);
+
+        findViewById(R.id.enable_trust).setOnClickListener(this);
+        findViewById(R.id.revoke_trust).setOnClickListener(this);
+
+        mReportUnlockAttempts = (CheckBox) findViewById(R.id.report_unlock_attempts);
+        mReportUnlockAttempts.setOnCheckedChangeListener(this);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mReportUnlockAttempts.setChecked(SampleTrustAgent.getReportUnlockAttempts(this));
+    }
+
+    @Override
+    public void onClick(View v) {
+        int id = v.getId();
+        if (id == R.id.enable_trust) {
+            SampleTrustAgent.sendEnableTrust(this, "SampleTrustAgent", TRUST_DURATION_MS,
+                    null /* extra */);
+        } else if (id == R.id.revoke_trust) {
+            SampleTrustAgent.sendRevokeTrust(this);
+        }
+    }
+
+    @Override
+    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+        if (buttonView.getId() == R.id.report_unlock_attempts) {
+            SampleTrustAgent.setReportUnlockAttempts(this, isChecked);
+        }
+    }
+}
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index f6e875c..f5ce222 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -26,7 +26,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="top|center_horizontal"
-        android:background="#88000000">
+        android:background="#e6444444">
         <ImageView
             android:id="@+id/activity_icon"
             android:layout_width="@dimen/recents_task_view_icon_size"
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index d7457f0..2e116d0 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -20,7 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"የስርዓት UI"</string>
-    <string name="status_bar_clear_all_button" msgid="7774721344716731603">"አጥራ"</string>
+    <string name="status_bar_clear_all_button" msgid="7774721344716731603">"አጽዳ"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"ከዝርዝር አስወግድ"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"የትግበራ መረጃ"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"ምንም የቅርብ ጊዜ ትግበራዎች የሉም"</string>
@@ -136,7 +136,7 @@
     <string name="accessibility_battery_level" msgid="7451474187113371965">"የባትሪ <xliff:g id="NUMBER">%d</xliff:g> መቶኛ።"</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"የስርዓት ቅንብሮች"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"ማሳወቂያዎች"</string>
-    <string name="accessibility_remove_notification" msgid="3603099514902182350">"ማሳወቂያ አጥራ"</string>
+    <string name="accessibility_remove_notification" msgid="3603099514902182350">"ማሳወቂያ አጽዳ"</string>
     <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS ነቅቷል።"</string>
     <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS በማግኘት ላይ።"</string>
     <string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter ነቅቷል።"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 7671ef1..289d6c6 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -188,8 +188,8 @@
     <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Bloccato in verticale"</string>
     <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Bloccato in orizzontale"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Metodo di immissione"</string>
-    <string name="quick_settings_location_label" msgid="5011327048748762257">"Geolocalizzazione"</string>
-    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Posizione non attiva"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Geolocalizz."</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Geolocalizz. non attiva"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Dispositivo multimediale"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Solo chiamate di emergenza"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 1dd9300..77ab17b 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -56,10 +56,10 @@
     <!-- Amount of time to hold off before showing the search panel when the user presses home -->
     <integer name="config_show_search_delay">200</integer>
 
-    <!-- Vibration duration for MultiWaveView used in SearchPanelView -->
+    <!-- Vibration duration for GlowPadView used in SearchPanelView -->
     <integer translatable="false" name="config_vibration_duration">0</integer>
 
-    <!-- Vibration duration for MultiWaveView used in SearchPanelView -->
+    <!-- Vibration duration for GlowPadView used in SearchPanelView -->
     <integer translatable="false" name="config_search_panel_view_vibration_duration">20</integer>
 
     <!-- The length of the vibration when the notification pops open. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a9b69854..38e1083 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -248,6 +248,6 @@
     <!-- Z distance between notifications if they are in the stack -->
     <dimen name="z_distance_between_notifications">2dp</dimen>
 
-    <!-- Width of the zen mode interstitial dialog.  Defaults to MATCH_PARENT. -->
-    <dimen name="zen_mode_dialog_width">-1px</dimen>
+    <!-- Width of the zen mode interstitial dialog. -->
+    <dimen name="zen_mode_dialog_width">320dp</dimen>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 48a6522..90b0c49 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -108,7 +108,7 @@
 
     private int mGravity;
 
-    private View mScrollView;
+    private ScrollAdapter mScrollAdapter;
 
     private OnScaleGestureListener mScaleGestureListener
             = new ScaleGestureDetector.SimpleOnScaleGestureListener() {
@@ -301,8 +301,8 @@
         mGravity = gravity;
     }
 
-    public void setScrollView(View scrollView) {
-        mScrollView = scrollView;
+    public void setScrollAdapter(ScrollAdapter adapter) {
+        mScrollAdapter = adapter;
     }
 
     private float calculateGlow(float target, float actual) {
@@ -384,7 +384,7 @@
                 }
                 return true;
             }
-            if (mScrollView != null && mScrollView.getScrollY() > 0) {
+            if (mScrollAdapter != null && !mScrollAdapter.isScrolledToTop()) {
                 return false;
             }
             // Now look for other gestures
@@ -407,7 +407,8 @@
             }
 
             case MotionEvent.ACTION_DOWN:
-                mWatchingForPull = isInside(mScrollView, x, y);
+                mWatchingForPull = mScrollAdapter != null &&
+                        isInside(mScrollAdapter.getHostView(), x, y);
                 mLastMotionY = y;
                 break;
 
@@ -608,5 +609,19 @@
         }
         mVibrator.vibrate(duration, AudioManager.STREAM_SYSTEM);
     }
+
+    public interface ScrollAdapter {
+
+        /**
+         * @return Whether the view returned by {@link #getHostView()} is scrolled to the top
+         * and can therefore be expanded by a single finger drag
+         */
+        public boolean isScrolledToTop();
+
+        /**
+         * @return The view in which the scrolling is performed
+         */
+        public View getHostView();
+    }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index 9d2d6ee..ab2ad96 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -368,7 +368,7 @@
         final ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
 
         final List<ActivityManager.RecentTaskInfo> recentTasks = am.getRecentTasksForUser(1,
-                ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_RELATED,
+                ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES,
                 UserHandle.CURRENT.getIdentifier());
         TaskDescription item = null;
         if (recentTasks.size() > 0) {
@@ -441,7 +441,7 @@
 
                 final List<ActivityManager.RecentTaskInfo> recentTasks =
                         am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE
-                        | ActivityManager.RECENT_INCLUDE_RELATED);
+                        | ActivityManager.RECENT_INCLUDE_PROFILES);
                 int numTasks = recentTasks.size();
                 ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN)
                         .addCategory(Intent.CATEGORY_HOME).resolveActivityInfo(pm, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
index f75ea92..7ab40b0 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
@@ -165,7 +165,7 @@
                     am.getRecentTasks(2,
                             ActivityManager.RECENT_WITH_EXCLUDED |
                             ActivityManager.RECENT_IGNORE_UNAVAILABLE |
-                            ActivityManager.RECENT_INCLUDE_RELATED);
+                            ActivityManager.RECENT_INCLUDE_PROFILES);
             if (recentTasks.size() > 1 &&
                     mRecentsPanel.simulateClick(recentTasks.get(1).persistentId)) {
                 // recents panel will take care of calling show(false) through simulateClick
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 1a616a0..227e19d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -221,7 +221,7 @@
     Bitmap loadFirstTaskThumbnail() {
         ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
         List<ActivityManager.RecentTaskInfo> tasks = am.getRecentTasksForUser(1,
-                ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_RELATED,
+                ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES,
                 UserHandle.CURRENT.getIdentifier());
         for (ActivityManager.RecentTaskInfo t : tasks) {
             // Skip tasks in the home stack
@@ -239,7 +239,7 @@
     boolean hasFirstTask() {
         ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
         List<ActivityManager.RecentTaskInfo> tasks = am.getRecentTasksForUser(1,
-                ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_RELATED,
+                ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES,
                 UserHandle.CURRENT.getIdentifier());
         for (ActivityManager.RecentTaskInfo t : tasks) {
             // Skip tasks in the home stack
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index b5950e9..2b08141 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -26,7 +26,7 @@
         public static final boolean Verbose = false;
 
         public static class App {
-            public static final boolean EnableTaskFiltering = false;
+            public static final boolean EnableTaskFiltering = true;
             public static final boolean EnableTaskStackClipping = false;
             public static final boolean EnableToggleNewRecentsActivity = false;
             // This disables the bitmap and icon caches to
@@ -81,6 +81,10 @@
             public static class Animation {
                 public static final int TaskRemovedReshuffleDuration = 200;
                 public static final int SnapScrollBackDuration = 650;
+                public static final int FilteredCurrentViewsDuration = 150;
+                public static final int FilteredNewViewsDuration = 200;
+                public static final int UnfilteredCurrentViewsDuration = 150;
+                public static final int UnfilteredNewViewsDuration = 200;
             }
 
             public static final int TaskStackOverscrollRange = 150;
@@ -107,7 +111,7 @@
             public static final boolean AnimateFrontTaskIconOnEnterRecents = true;
             public static final boolean AnimateFrontTaskIconOnLeavingRecents = true;
 
-            public static final boolean UseRoundedCorners = true;
+            public static final boolean UseRoundedCorners = false;
             public static final float RoundedCornerRadiusDps = 3;
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index b65b864..dd75921 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -54,8 +54,11 @@
                     finish();
                 }
             } else if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
-                // Dismiss recents and launch the first task if possible
-                dismissRecentsIfVisible();
+                // Try and unfilter and filtered stacks
+                if (!mRecentsView.unfilterFilteredStacks()) {
+                    // If there are no filtered stacks, dismiss recents and launch the first task
+                    dismissRecentsIfVisible();
+                }
             }
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index 515cec1..22363bb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -66,7 +66,7 @@
                 // in a bottom inset
                 tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0);
                 tsv.boundScroll();
-                TaskViewTransform transform = tsv.getStackTransform(0);
+                TaskViewTransform transform = tsv.getStackTransform(0, tsv.getStackScroll());
                 Rect taskRect = new Rect(transform.rect);
 
                 data.putParcelable("taskRect", taskRect);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index b497b69..928c732 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -190,7 +190,7 @@
                         // Load the icon
                         if (loadIcon == null || forceLoadTask) {
                             PackageManager pm = mContext.getPackageManager();
-                            ActivityInfo info = pm.getActivityInfo(t.key.intent.getComponent(),
+                            ActivityInfo info = pm.getActivityInfo(t.key.baseIntent.getComponent(),
                                     PackageManager.GET_META_DATA);
                             Drawable icon = info.loadIcon(pm);
                             if (!mCancelled) {
@@ -218,7 +218,7 @@
                                 } else {
                                     Console.logError(mContext,
                                             "Failed to load task top thumbnail for: " +
-                                                    t.key.intent.getComponent().getPackageName());
+                                                    t.key.baseIntent.getComponent().getPackageName());
                                 }
                             }
                         }
@@ -376,7 +376,7 @@
             // Get the recent tasks
             List<ActivityManager.RecentTaskInfo> tasks = am.getRecentTasksForUser(25,
                     ActivityManager.RECENT_IGNORE_UNAVAILABLE |
-                    ActivityManager.RECENT_INCLUDE_RELATED, UserHandle.CURRENT.getIdentifier());
+                    ActivityManager.RECENT_INCLUDE_PROFILES, UserHandle.CURRENT.getIdentifier());
             Collections.reverse(tasks);
             Console.log(Constants.DebugFlags.App.TimeSystemCalls,
                     "[RecentsTaskLoader|getRecentTasks]",
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
index 33e4246..9048cba 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
@@ -20,9 +20,6 @@
 
 /* Common code */
 public class Utilities {
-    public static final Rect tmpRect = new Rect();
-    public static final Rect tmpRect2 = new Rect();
-
     /** Scales a rect about its centroid */
     public static void scaleRectAboutCenter(Rect r, float scale) {
         if (scale != 1.0f) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index cda4ab2..677334d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -37,11 +37,11 @@
     /* The Task Key represents the unique primary key for the task */
     public static class TaskKey {
         public final int id;
-        public final Intent intent;
+        public final Intent baseIntent;
 
         public TaskKey(int id, Intent intent) {
             this.id = id;
-            this.intent = intent;
+            this.baseIntent = intent;
         }
 
         @Override
@@ -56,7 +56,7 @@
 
         @Override
         public String toString() {
-            return "Task.Key: " + id + ", " + intent.getComponent().getPackageName();
+            return "Task.Key: " + id + ", " + baseIntent.getComponent().getPackageName();
         }
     }
 
@@ -120,6 +120,6 @@
 
     @Override
     public String toString() {
-        return "Task: " + key.intent.getComponent().getPackageName() + " [" + super.toString() + "]";
+        return "Task: " + key.baseIntent.getComponent().getPackageName() + " [" + super.toString() + "]";
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index f2f89ae..a0e5b6a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -39,9 +39,11 @@
     TaskFilter mFilter;
 
     /** Sets the task filter, saving the current touch state */
-    void setFilter(TaskFilter filter) {
+    boolean setFilter(TaskFilter filter) {
+        ArrayList<Task> prevFilteredTasks = new ArrayList<Task>(mFilteredTasks);
         mFilter = filter;
         updateFilteredTasks();
+        return !prevFilteredTasks.equals(mFilteredTasks);
     }
 
     /** Removes the task filter and returns the previous touch state */
@@ -126,9 +128,9 @@
         /* Notifies when a task has been removed from the stack */
         public void onStackTaskRemoved(TaskStack stack, Task t);
         /** Notifies when the stack was filtered */
-        public void onStackFiltered(TaskStack stack);
+        public void onStackFiltered(TaskStack newStack, ArrayList<Task> curStack, Task t);
         /** Notifies when the stack was un-filtered */
-        public void onStackUnfiltered(TaskStack stack);
+        public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curStack);
     }
 
     Context mContext;
@@ -201,29 +203,30 @@
     }
 
     /** Filters the stack into tasks similar to the one specified */
-    public void filterTasks(Task t) {
+    public void filterTasks(final Task t) {
+        ArrayList<Task> oldStack = new ArrayList<Task>(mTaskList.getTasks());
+
         // Set the task list filter
-        // XXX: This is a dummy filter that currently just accepts every other task.
-        mTaskList.setFilter(new TaskFilter() {
+        boolean filtered = mTaskList.setFilter(new TaskFilter() {
             @Override
-            public boolean acceptTask(Task t, int i) {
-                if (i % 2 == 0) {
-                    return true;
-                }
-                return false;
+            public boolean acceptTask(Task at, int i) {
+                return t.key.baseIntent.getComponent().getPackageName().equals(
+                        at.key.baseIntent.getComponent().getPackageName());
             }
         });
-        if (mCb != null) {
-            mCb.onStackFiltered(this);
+        if (filtered && mCb != null) {
+            mCb.onStackFiltered(this, oldStack, t);
         }
     }
 
     /** Unfilters the current stack */
     public void unfilterTasks() {
+        ArrayList<Task> oldStack = new ArrayList<Task>(mTaskList.getTasks());
+
         // Unset the filter, then update the virtual scroll
         mTaskList.removeFilter();
         if (mCb != null) {
-            mCb.onStackUnfiltered(this);
+            mCb.onStackUnfiltered(this, oldStack);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index cc85439..e89bde5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -211,17 +211,18 @@
                 View sourceView = tv;
                 int offsetX = 0;
                 int offsetY = 0;
+                int stackScroll = stackView.getStackScroll();
                 if (tv == null) {
                     // If there is no actual task view, then use the stack view as the source view
                     // and then offset to the expected transform rect, but bound this to just
                     // outside the display rect (to ensure we don't animate from too far away)
                     RecentsConfiguration config = RecentsConfiguration.getInstance();
                     sourceView = stackView;
-                    transform = stackView.getStackTransform(stack.indexOfTask(task));
+                    transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll);
                     offsetX = transform.rect.left;
                     offsetY = Math.min(transform.rect.top, config.displayRect.height());
                 } else {
-                    transform = stackView.getStackTransform(stack.indexOfTask(task));
+                    transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll);
                 }
 
                 // Compute the thumbnail to scale up from
@@ -255,7 +256,7 @@
                     }
                 } else {
                     // Launch the activity with the desired animation
-                    Intent i = new Intent(task.key.intent);
+                    Intent i = new Intent(task.key.baseIntent);
                     i.setFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
                             | Intent.FLAG_ACTIVITY_TASK_ON_HOME
                             | Intent.FLAG_ACTIVITY_NEW_TASK);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index e7f517f..aeb571d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -18,6 +18,7 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.app.Activity;
@@ -34,6 +35,7 @@
 import android.view.ViewParent;
 import android.widget.FrameLayout;
 import android.widget.OverScroller;
+import com.android.systemui.R;
 import com.android.systemui.recents.Console;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
@@ -41,7 +43,6 @@
 import com.android.systemui.recents.Utilities;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.R;
 
 import java.util.ArrayList;
 
@@ -71,6 +72,7 @@
     int mStackScroll;
     int mMinScroll;
     int mMaxScroll;
+    int mStashedScroll;
     OverScroller mScroller;
     ObjectAnimator mScrollAnimator;
 
@@ -79,6 +81,9 @@
     int mStackViewsAnimationDuration;
     boolean mStackViewsDirty = true;
     boolean mAwaitingFirstLayout = true;
+    int[] mTmpVisibleRange = new int[2];
+    Rect mTmpRect = new Rect();
+    Rect mTmpRect2 = new Rect();
     LayoutInflater mInflater;
 
     public TaskStackView(Context context, TaskStack stack) {
@@ -102,7 +107,7 @@
     }
     void requestSynchronizeStackViewsWithModel(int duration) {
         Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
-                "[TaskStackView|requestSynchronize]", "", Console.AnsiYellow);
+                "[TaskStackView|requestSynchronize]", "" + duration + "ms", Console.AnsiYellow);
         if (!mStackViewsDirty) {
             invalidate();
         }
@@ -128,14 +133,17 @@
     }
 
     /** Update/get the transform */
-    public TaskViewTransform getStackTransform(int indexInStack) {
+    public TaskViewTransform getStackTransform(int indexInStack, int stackScroll) {
         TaskViewTransform transform = new TaskViewTransform();
 
-        // Map the items to an continuous position relative to the current scroll
+        // Return early if we have an invalid index
+        if (indexInStack < 0) return transform;
+
+        // Map the items to an continuous position relative to the specified scroll
         int numPeekCards = Constants.Values.TaskStackView.StackPeekNumCards;
         float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height();
         float peekHeight = Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height();
-        float t = ((indexInStack * overlapHeight) - getStackScroll()) / overlapHeight;
+        float t = ((indexInStack * overlapHeight) - stackScroll) / overlapHeight;
         float boundedT = Math.max(t, -(numPeekCards + 1));
 
         // Set the scale relative to its position
@@ -167,25 +175,57 @@
         return transform;
     }
 
+    /**
+     * Gets the stack transforms of a list of tasks, and returns the visible range of tasks.
+     */
+    private ArrayList<TaskViewTransform> getStackTransforms(ArrayList<Task> tasks,
+                                                            int stackScroll,
+                                                            int[] visibleRangeOut) {
+        // XXX: Optimization: Use binary search to find the visible range
+
+        ArrayList<TaskViewTransform> taskTransforms = new ArrayList<TaskViewTransform>();
+        int taskCount = tasks.size();
+        int firstVisibleIndex = -1;
+        int lastVisibleIndex = -1;
+        for (int i = 0; i < taskCount; i++) {
+            TaskViewTransform transform = getStackTransform(i, stackScroll);
+            taskTransforms.add(transform);
+            if (transform.visible) {
+                if (firstVisibleIndex < 0) {
+                    firstVisibleIndex = i;
+                }
+                lastVisibleIndex = i;
+            }
+        }
+        if (visibleRangeOut != null) {
+            visibleRangeOut[0] = firstVisibleIndex;
+            visibleRangeOut[1] = lastVisibleIndex;
+        }
+        return taskTransforms;
+    }
+
     /** Synchronizes the views with the model */
     void synchronizeStackViewsWithModel() {
         Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
                 "[TaskStackView|synchronizeViewsWithModel]",
                 "mStackViewsDirty: " + mStackViewsDirty, Console.AnsiYellow);
         if (mStackViewsDirty) {
-
-            // XXX: Optimization: Use binary search to find the visible range
-            // XXX: Optimize to not call getStackTransform() so many times
             // XXX: Consider using TaskViewTransform pool to prevent allocations
             // XXX: Iterate children views, update transforms and remove all that are not visible
             //      For all remaining tasks, update transforms and if visible add the view
 
-            // Update the visible state of all the tasks
+            // Get all the task transforms
+            int[] visibleRange = mTmpVisibleRange;
+            int stackScroll = getStackScroll();
             ArrayList<Task> tasks = mStack.getTasks();
+            ArrayList<TaskViewTransform> taskTransforms = getStackTransforms(tasks, stackScroll,
+                    visibleRange);
+
+            // Update the visible state of all the tasks
             int taskCount = tasks.size();
             for (int i = 0; i < taskCount; i++) {
                 Task task = tasks.get(i);
-                TaskViewTransform transform = getStackTransform(i);
+                TaskViewTransform transform = taskTransforms.get(i);
                 TaskView tv = getChildViewForTask(task);
 
                 if (transform.visible) {
@@ -194,11 +234,9 @@
                         // When we are picking up a new view from the view pool, prepare it for any
                         // following animation by putting it in a reasonable place
                         if (mStackViewsAnimationDuration > 0 && i != 0) {
-                            // XXX: We have to animate when filtering, etc. Maybe we should have a
-                            //      runnable that ensures that tasks are animated in a special way
-                            //      when they are entering the scene?
                             int fromIndex = (transform.t < 0) ? (i - 1) : (i + 1);
-                            tv.updateViewPropertiesFromTask(null, getStackTransform(fromIndex), 0);
+                            tv.updateViewPropertiesToTaskTransform(null,
+                                    getStackTransform(fromIndex, stackScroll), 0);
                         }
                     }
                 } else {
@@ -208,17 +246,18 @@
                 }
             }
 
-            // Update all the current view children
+            // Update all the remaining view children
             // NOTE: We have to iterate in reverse where because we are removing views directly
             int childCount = getChildCount();
             for (int i = childCount - 1; i >= 0; i--) {
                 TaskView tv = (TaskView) getChildAt(i);
                 Task task = tv.getTask();
-                TaskViewTransform transform = getStackTransform(mStack.indexOfTask(task));
-                if (!transform.visible) {
+                int taskIndex = mStack.indexOfTask(task);
+                if (taskIndex < 0 || !taskTransforms.get(taskIndex).visible) {
                     mViewPool.returnViewToPool(tv);
                 } else {
-                    tv.updateViewPropertiesFromTask(null, transform, mStackViewsAnimationDuration);
+                    tv.updateViewPropertiesToTaskTransform(null, taskTransforms.get(taskIndex),
+                            mStackViewsAnimationDuration);
                 }
             }
 
@@ -235,6 +274,10 @@
         mStackScroll = value;
         requestSynchronizeStackViewsWithModel();
     }
+    /** Sets the current stack scroll without synchronizing the stack view with the model */
+    public void setStackScrollRaw(int value) {
+        mStackScroll = value;
+    }
 
     /** Gets the current stack scroll */
     public int getStackScroll() {
@@ -251,36 +294,39 @@
 
             // Abort any current animations
             abortScroller();
-            if (mScrollAnimator != null) {
-                mScrollAnimator.cancel();
-                mScrollAnimator.removeAllListeners();
-            }
+            abortBoundScrollAnimation();
 
             // Start a new scroll animation
-            mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll);
-            mScrollAnimator.setDuration(duration);
-            mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    setStackScroll((Integer) animation.getAnimatedValue());
-                }
-            });
-            mScrollAnimator.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    // Disable hw layers on the stack
-                    decHwLayersRefCount("animateBoundScroll");
-                }
-            });
+            animateScroll(curScroll, newScroll, duration);
             mScrollAnimator.start();
         }
         return mScrollAnimator;
     }
 
+    /** Animates the stack scroll */
+    void animateScroll(int curScroll, int newScroll, int duration) {
+        mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll);
+        mScrollAnimator.setDuration(duration);
+        mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                setStackScroll((Integer) animation.getAnimatedValue());
+            }
+        });
+        mScrollAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                // Disable hw layers on the stack
+                decHwLayersRefCount("animateBoundScroll");
+            }
+        });
+    }
+
     /** Aborts any current stack scrolls */
     void abortBoundScrollAnimation() {
         if (mScrollAnimator != null) {
             mScrollAnimator.cancel();
+            mScrollAnimator.removeAllListeners();
         }
     }
 
@@ -304,6 +350,20 @@
         return false;
     }
 
+    /**
+     * Bounds the current scroll if necessary, but does not synchronize the stack view with the
+     * model.
+     */
+    public boolean boundScrollRaw() {
+        int curScroll = getStackScroll();
+        int newScroll = Math.max(mMinScroll, Math.min(mMaxScroll, curScroll));
+        if (newScroll != curScroll) {
+            setStackScrollRaw(newScroll);
+            return true;
+        }
+        return false;
+    }
+
     /** Returns whether the current scroll is out of bounds */
     boolean isScrollOutOfBounds() {
         return (getStackScroll() < 0) || (getStackScroll() > mMaxScroll);
@@ -404,12 +464,12 @@
             TaskView tv = (TaskView) child;
             TaskView nextTv = null;
             int curIndex = indexOfChild(tv);
-            if (curIndex < (getChildCount() - 1)) {
+            if ((curIndex > -1) && (curIndex < (getChildCount() - 1))) {
                 // Clip against the next view (if we aren't animating its alpha)
                 nextTv = (TaskView) getChildAt(curIndex + 1);
                 if (nextTv.getAlpha() == 1f) {
-                    Rect curRect = tv.getClippingRect(Utilities.tmpRect, false);
-                    Rect nextRect = nextTv.getClippingRect(Utilities.tmpRect2, true);
+                    Rect curRect = tv.getClippingRect(mTmpRect, false);
+                    Rect nextRect = nextTv.getClippingRect(mTmpRect2, true);
                     RecentsConfiguration config = RecentsConfiguration.getInstance();
                     // The hit rects are relative to the task view, which needs to be offset by the
                     // system bar height
@@ -528,9 +588,7 @@
                     mTaskRect.right, mStackRectSansPeek.top + mTaskRect.height());
         }
 
-        if (!mAwaitingFirstLayout) {
-            requestSynchronizeStackViewsWithModel();
-        } else {
+        if (mAwaitingFirstLayout) {
             mAwaitingFirstLayout = false;
         }
     }
@@ -570,13 +628,185 @@
     }
 
     @Override
-    public void onStackFiltered(TaskStack stack) {
-        requestSynchronizeStackViewsWithModel();
+    public void onStackFiltered(TaskStack newStack, final ArrayList<Task> curStack,
+                                Task filteredTask) {
+        // NOTE: This code assumes that the current (unfiltered) stack is a superset of the new
+        // (filtered) stack
+        // XXX: Use HW Layers
+
+        // Stash the scroll for us to restore to when we unfilter
+        mStashedScroll = getStackScroll();
+
+        // Compute the transforms of the items in the current stack
+        final ArrayList<TaskViewTransform> curTaskTransforms =
+                getStackTransforms(curStack, mStashedScroll, null);
+
+        // Bound the new stack scroll
+        updateMinMaxScroll(false);
+        boundScrollRaw();
+
+        // Compute the transforms of the items in the new stack
+        final ArrayList<TaskViewTransform> taskTransforms =
+                getStackTransforms(mStack.getTasks(), getStackScroll(), null);
+
+        // Animate all of the existing views on screen either out of view (if they are not visible
+        // in the new stack) or to their final positions in the new stack
+        final ArrayList<TaskView> childrenToReturnToPool = new ArrayList<TaskView>();
+        final ArrayList<Task> tasks = mStack.getTasks();
+        ArrayList<Animator> childViewAnims = new ArrayList<Animator>();
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            TaskView tv = (TaskView) getChildAt(i);
+            Task task = tv.getTask();
+            TaskViewTransform toTransform;
+            int taskIndex = tasks.indexOf(task);
+            if ((taskIndex < 0) || !taskTransforms.get(taskIndex).visible) {
+                // Compose a new transform that animates the task view out of view
+                TaskViewTransform fromTransform = curTaskTransforms.get(curStack.indexOf(task));
+                toTransform = new TaskViewTransform(fromTransform);
+                tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
+                tv.prepareTaskTransformForFilterTaskHidden(toTransform);
+
+                childrenToReturnToPool.add(tv);
+            } else {
+                toTransform = taskTransforms.get(taskIndex);
+            }
+            childViewAnims.add(tv.getAnimatorToTaskTransform(toTransform));
+        }
+
+        AnimatorSet childViewAnimSet = new AnimatorSet();
+        childViewAnimSet.setDuration(
+                Constants.Values.TaskStackView.Animation.FilteredCurrentViewsDuration);
+        childViewAnimSet.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                // Return all the removed children to the view pool
+                for (TaskView tv : childrenToReturnToPool) {
+                    mViewPool.returnViewToPool(tv);
+                }
+
+                // For views that are not already visible, animate them in
+                int taskCount = tasks.size();
+                for (int i = 0; i < taskCount; i++) {
+                    Task task = tasks.get(i);
+                    TaskViewTransform toTransform = taskTransforms.get(i);
+                    if (toTransform.visible) {
+                        TaskViewTransform fromTransform =
+                                curTaskTransforms.get(curStack.indexOf(task));
+                        TaskView tv = getChildViewForTask(task);
+                        if (tv == null) {
+                            tv = mViewPool.pickUpViewFromPool(task, task);
+
+                            // Animate from the current position to the new position
+                            tv.prepareTaskTransformForFilterTaskVisible(fromTransform);
+                            tv.updateViewPropertiesToTaskTransform(fromTransform,
+                                    toTransform,
+                                    Constants.Values.TaskStackView.Animation.FilteredNewViewsDuration);
+                        }
+                    }
+                }
+                invalidate();
+            }
+        });
+        childViewAnimSet.playTogether(childViewAnims);
+        childViewAnimSet.start();
     }
 
     @Override
-    public void onStackUnfiltered(TaskStack stack) {
-        requestSynchronizeStackViewsWithModel();
+    public void onStackUnfiltered(TaskStack newStack, final ArrayList<Task> curStack) {
+        // Compute the transforms of the items in the current stack
+        final int curScroll = getStackScroll();
+        final ArrayList<TaskViewTransform> curTaskTransforms =
+                getStackTransforms(curStack, curScroll, null);
+
+        // Restore the stashed scroll
+        updateMinMaxScroll(false);
+        setStackScrollRaw(mStashedScroll);
+        boundScrollRaw();
+
+        // Compute the transforms of the items in the new stack
+        final ArrayList<TaskViewTransform> taskTransforms =
+                getStackTransforms(mStack.getTasks(), getStackScroll(), null);
+
+        // Animate all of the existing views out of view (if they are not in the visible range in
+        // the new stack) or to their final positions in the new stack
+        final ArrayList<TaskView> childrenToRemove = new ArrayList<TaskView>();
+        final ArrayList<Task> tasks = mStack.getTasks();
+        ArrayList<Animator> childViewAnims = new ArrayList<Animator>();
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            TaskView tv = (TaskView) getChildAt(i);
+            Task task = tv.getTask();
+            int taskIndex = tasks.indexOf(task);
+            TaskViewTransform transform;
+
+            // If the view is no longer visible, then we should just animate it out
+            if (taskIndex < 0 || !taskTransforms.get(taskIndex).visible) {
+                transform = new TaskViewTransform(curTaskTransforms.get(curStack.indexOf(task)));
+                tv.prepareTaskTransformForFilterTaskVisible(transform);
+                childrenToRemove.add(tv);
+            } else {
+                transform = taskTransforms.get(taskIndex);
+            }
+            childViewAnims.add(tv.getAnimatorToTaskTransform(transform));
+        }
+
+        AnimatorSet childViewAnimSet = new AnimatorSet();
+        childViewAnimSet.setDuration(
+                Constants.Values.TaskStackView.Animation.UnfilteredCurrentViewsDuration);
+        childViewAnimSet.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                // Return all the removed children to the view pool
+                for (TaskView tv : childrenToRemove) {
+                    mViewPool.returnViewToPool(tv);
+                }
+
+                // Increment the hw layers ref count
+                addHwLayersRefCount("unfilteredNewViews");
+
+                // For views that are not already visible, animate them in
+                ArrayList<Animator> newViewAnims = new ArrayList<Animator>();
+                AnimatorSet newViewAnimSet = new AnimatorSet();
+                int taskCount = tasks.size();
+                int offset = 0;
+                for (int i = 0; i < taskCount; i++) {
+                    Task task = tasks.get(i);
+                    TaskViewTransform toTransform = taskTransforms.get(i);
+                    if (toTransform.visible) {
+                        TaskView tv = getChildViewForTask(task);
+                        if (tv == null) {
+                            // For views that are not already visible, animate them in
+                            tv = mViewPool.pickUpViewFromPool(task, task);
+
+                            // Animate in this new view
+                            TaskViewTransform fromTransform = new TaskViewTransform(toTransform);
+                            tv.prepareTaskTransformForFilterTaskHidden(fromTransform);
+                            tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
+                            newViewAnims.add(tv.getAnimatorToTaskTransform(toTransform));
+                            offset++;
+                        }
+                    }
+                }
+
+                // Run the animation
+                newViewAnimSet.setDuration(
+                        Constants.Values.TaskStackView.Animation.UnfilteredNewViewsDuration);
+                newViewAnimSet.playTogether(newViewAnims);
+                newViewAnimSet.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        // Decrement the hw layers ref count
+                        decHwLayersRefCount("unfilteredNewViews");
+                    }
+                });
+                newViewAnimSet.start();
+
+                invalidate();
+            }
+        });
+        childViewAnimSet.playTogether(childViewAnims);
+        childViewAnimSet.start();
     }
 
     /**** ViewPoolConsumer Implementation ****/
@@ -845,7 +1075,7 @@
 
     /** Handles touch events once we have intercepted them */
     public boolean onTouchEvent(MotionEvent ev) {
-        Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
+        Console.log(Constants.DebugFlags.UI.TouchEvents,
                 "[TaskStackViewTouchHandler|touchEvent]",
                 Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
 
@@ -1045,9 +1275,17 @@
                     ActivityManager.REMOVE_TASK_KILL_PROCESS);
         }
 
-        // If there are no remaining tasks, then just close the activity
+        // If there are no remaining tasks, then either unfilter the current stack, or just close
+        // the activity if there are no filtered stacks
         if (mSv.mStack.getTaskCount() == 0) {
-            activity.finish();
+            boolean shouldFinishActivity = true;
+            if (mSv.mStack.hasFilteredTasks()) {
+                mSv.mStack.unfilterTasks();
+                shouldFinishActivity = (mSv.mStack.getTaskCount() == 0);
+            }
+            if (shouldFinishActivity) {
+                activity.finish();
+            }
         }
 
         // Disable HW layers
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index c86b0e1..e04a1b2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.recents.views;
 
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Path;
@@ -72,6 +75,7 @@
         // Bind the views
         mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail);
         mBarView = (TaskBarView) findViewById(R.id.task_view_bar);
+        mBarView.mActivityIcon.setOnClickListener(this);
         if (mTaskDataLoaded) {
             onTaskDataLoaded(false);
         }
@@ -90,12 +94,16 @@
     }
 
     @Override
-    protected void onDraw(Canvas canvas) {
+    protected void dispatchDraw(Canvas canvas) {
+        int restoreCount = 0;
         if (Constants.Values.TaskView.UseRoundedCorners) {
+            restoreCount = canvas.save();
             canvas.clipPath(mRoundedRectClipPath);
         }
-
-        super.onDraw(canvas);
+        super.dispatchDraw(canvas);
+        if (Constants.Values.TaskView.UseRoundedCorners) {
+            canvas.restoreToCount(restoreCount);
+        }
     }
 
     /** Set callback */
@@ -109,27 +117,43 @@
     }
 
     /** Synchronizes this view's properties with the task's transform */
-    void updateViewPropertiesFromTask(TaskViewTransform animateFromTransform,
-                                      TaskViewTransform transform, int duration) {
+    void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
+                                             TaskViewTransform toTransform, int duration) {
         if (duration > 0) {
             if (animateFromTransform != null) {
                 setTranslationY(animateFromTransform.translationY);
                 setScaleX(animateFromTransform.scale);
                 setScaleY(animateFromTransform.scale);
+                setAlpha(animateFromTransform.alpha);
             }
-            animate().translationY(transform.translationY)
-                    .scaleX(transform.scale)
-                    .scaleY(transform.scale)
+            animate().translationY(toTransform.translationY)
+                    .scaleX(toTransform.scale)
+                    .scaleY(toTransform.scale)
+                    .alpha(toTransform.alpha)
                     .setDuration(duration)
                     .setInterpolator(new AccelerateDecelerateInterpolator())
+                    .withLayer()
                     .start();
         } else {
-            setTranslationY(transform.translationY);
-            setScaleX(transform.scale);
-            setScaleY(transform.scale);
+            setTranslationY(toTransform.translationY);
+            setScaleX(toTransform.scale);
+            setScaleY(toTransform.scale);
+            setAlpha(toTransform.alpha);
         }
     }
 
+    /** Returns an animator to animate this task to the specified transform */
+    Animator getAnimatorToTaskTransform(TaskViewTransform toTransform) {
+        AnimatorSet anims = new AnimatorSet();
+        anims.playTogether(
+                ObjectAnimator.ofFloat(this, "translationY", toTransform.translationY),
+                ObjectAnimator.ofFloat(this, "scaleX", toTransform.scale),
+                ObjectAnimator.ofFloat(this, "scaleY", toTransform.scale),
+                ObjectAnimator.ofFloat(this, "alpha", toTransform.alpha)
+        );
+        return anims;
+    }
+
     /** Resets this view's properties */
     void resetViewProperties() {
         setTranslationX(0f);
@@ -139,6 +163,17 @@
         setAlpha(1f);
     }
 
+    void prepareTaskTransformForFilterTaskHidden(TaskViewTransform toTransform) {
+        // Fade the view out and slide it away
+        toTransform.alpha = 0f;
+        toTransform.translationY += 200;
+    }
+
+    void prepareTaskTransformForFilterTaskVisible(TaskViewTransform fromTransform) {
+        // Fade the view in
+        fromTransform.alpha = 0f;
+    }
+
     /** Animates this task view as it enters recents */
     public void animateOnEnterRecents() {
         RecentsConfiguration config = RecentsConfiguration.getInstance();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index 66c52a0..0748bbb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -23,13 +23,27 @@
 public class TaskViewTransform {
     public int translationY = 0;
     public float scale = 1f;
-    public boolean visible = true;
+    public float alpha = 1f;
+    public boolean visible = false;
     public Rect rect = new Rect();
     float t;
 
+    public TaskViewTransform() {
+        // Do nothing
+    }
+
+    public TaskViewTransform(TaskViewTransform o) {
+        translationY = o.translationY;
+        scale = o.scale;
+        alpha = o.alpha;
+        visible = o.visible;
+        rect.set(o.rect);
+        t = o.t;
+    }
+
     @Override
     public String toString() {
-        return "TaskViewTransform y: " + translationY + " scale: " + scale +
+        return "TaskViewTransform y: " + translationY + " scale: " + scale + " alpha: " + alpha +
                 " visible: " + visible + " rect: " + rect;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index bad5641..e5e287d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -134,7 +134,7 @@
     protected PopupMenu mNotificationBlamePopup;
 
     protected int mCurrentUserId = 0;
-    final protected SparseArray<UserInfo> mRelatedUsers = new SparseArray<UserInfo>();
+    final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
 
     protected int mLayoutDirection = -1; // invalid
     private Locale mLocale;
@@ -244,21 +244,21 @@
             String action = intent.getAction();
             if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                 mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
-                updateRelatedUserCache();
+                updateCurrentProfilesCache();
                 if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
                 userSwitched(mCurrentUserId);
             } else if (Intent.ACTION_USER_ADDED.equals(action)) {
-                updateRelatedUserCache();
+                updateCurrentProfilesCache();
             }
         }
     };
 
-    private void updateRelatedUserCache() {
-        synchronized (mRelatedUsers) {
-            mRelatedUsers.clear();
+    private void updateCurrentProfilesCache() {
+        synchronized (mCurrentProfiles) {
+            mCurrentProfiles.clear();
             if (mUserManager != null) {
-                for (UserInfo related : mUserManager.getRelatedUsers(mCurrentUserId)) {
-                    mRelatedUsers.put(related.id, related);
+                for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
+                    mCurrentProfiles.put(user.id, user);
                 }
             }
         }
@@ -361,24 +361,23 @@
         filter.addAction(Intent.ACTION_USER_ADDED);
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
-        updateRelatedUserCache();
+        updateCurrentProfilesCache();
     }
 
     public void userSwitched(int newUserId) {
         // should be overridden
     }
 
-    public boolean notificationIsForCurrentOrRelatedUser(StatusBarNotification n) {
+    public boolean notificationIsForCurrentProfiles(StatusBarNotification n) {
         final int thisUserId = mCurrentUserId;
         final int notificationUserId = n.getUserId();
         if (DEBUG && MULTIUSER_DEBUG) {
             Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
                     n, thisUserId, notificationUserId));
         }
-        synchronized (mRelatedUsers) {
+        synchronized (mCurrentProfiles) {
             return notificationUserId == UserHandle.USER_ALL
-                    || thisUserId == notificationUserId
-                    || mRelatedUsers.get(notificationUserId) != null;
+                    || mCurrentProfiles.get(notificationUserId) != null;
         }
     }
 
@@ -1258,7 +1257,7 @@
         updateNotificationVetoButton(oldEntry.row, notification);
 
         // Is this for you?
-        boolean isForCurrentUser = notificationIsForCurrentOrRelatedUser(notification);
+        boolean isForCurrentUser = notificationIsForCurrentProfiles(notification);
         if (DEBUG) Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
 
         // Restart the ticker if it's still running
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 160f2be..2257aaa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -80,7 +80,6 @@
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.ScrollView;
 import android.widget.TextView;
 
 import com.android.internal.statusbar.StatusBarIcon;
@@ -199,7 +198,7 @@
 
     // expanded notifications
     NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
-    ScrollView mScrollView;
+    View mNotificationScroller;
     View mExpandedContents;
     int mNotificationPanelGravity;
     int mNotificationPanelMarginBottomPx, mNotificationPanelMarginPx;
@@ -483,15 +482,24 @@
         mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents);
         mTickerView = mStatusBarView.findViewById(R.id.ticker);
 
-        NotificationRowLayout rowLayout
-                = (NotificationRowLayout) mStatusBarWindow.findViewById(R.id.latestItems);
+        View legacyScrollView = mStatusBarWindow.findViewById(R.id.scroll);
         NotificationStackScrollLayout notificationStack
                 = (NotificationStackScrollLayout) mStatusBarWindow
                 .findViewById(R.id.notification_stack_scroller);
         if (ENABLE_NOTIFICATION_STACK) {
             notificationStack.setLongPressListener(getNotificationLongClicker());
             mPile = notificationStack;
+            legacyScrollView.setVisibility(View.GONE);
+
+            // The scrollview and the notification container are unified now!
+            // TODO: remove mNotificationScroller entirely once we fully switch to the new Layout
+            mNotificationScroller = notificationStack;
         } else {
+            mNotificationScroller = legacyScrollView;
+            // less drawing during pulldowns
+            mNotificationScroller.setVerticalScrollBarEnabled(false);
+            NotificationRowLayout rowLayout
+                    = (NotificationRowLayout) mStatusBarWindow.findViewById(R.id.latestItems);
             rowLayout.setLayoutTransitionsEnabled(false);
             rowLayout.setLongPressListener(getNotificationLongClicker());
             mPile = rowLayout;
@@ -549,10 +557,8 @@
             }
         }
 
-        mScrollView = (ScrollView)mStatusBarWindow.findViewById(R.id.scroll);
-        mScrollView.setVerticalScrollBarEnabled(false); // less drawing during pulldowns
         if (!mNotificationPanelIsFullScreenWidth) {
-            mScrollView.setSystemUiVisibility(
+            mNotificationPanel.setSystemUiVisibility(
                     View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS |
                     View.STATUS_BAR_DISABLE_CLOCK);
         }
@@ -615,7 +621,7 @@
             }
 
             // set up the dynamic hide/show of the label
-            if(!ENABLE_NOTIFICATION_STACK)
+            if (!ENABLE_NOTIFICATION_STACK)
                 ((NotificationRowLayout) mPile).setOnSizeChangedListener(new OnSizeChangedListener() {
                 @Override
                 public void onSizeChanged(View view, int w, int h, int oldw, int oldh) {
@@ -1072,8 +1078,8 @@
             Entry ent = mNotificationData.get(N-i-1);
             if (!(provisioned || showNotificationEvenIfUnprovisioned(ent.notification))) continue;
 
-            // TODO How do we want to badge notifcations from related users.
-            if (!notificationIsForCurrentOrRelatedUser(ent.notification)) continue;
+            // TODO How do we want to badge notifcations from profiles.
+            if (!notificationIsForCurrentProfiles(ent.notification)) continue;
 
             final int vis = ent.notification.getNotification().visibility;
             if (vis != Notification.VISIBILITY_SECRET) {
@@ -1132,7 +1138,7 @@
             Entry ent = mNotificationData.get(N-i-1);
             if (!((provisioned && ent.notification.getScore() >= HIDE_ICONS_BELOW_SCORE)
                     || showNotificationEvenIfUnprovisioned(ent.notification))) continue;
-            if (!notificationIsForCurrentOrRelatedUser(ent.notification)) continue;
+            if (!notificationIsForCurrentProfiles(ent.notification)) continue;
             if (isLockscreenPublicMode()
                     && ent.notification.getNotification().visibility
                             == Notification.VISIBILITY_SECRET
@@ -1167,19 +1173,20 @@
     }
 
     protected void updateCarrierLabelVisibility(boolean force) {
+        // TODO: Handle this for the notification stack scroller as well
         if (!mShowCarrierInPanel) return;
         // The idea here is to only show the carrier label when there is enough room to see it,
         // i.e. when there aren't enough notifications to fill the panel.
         if (SPEW) {
             Log.d(TAG, String.format("pileh=%d scrollh=%d carrierh=%d",
-                    mPile.getHeight(), mScrollView.getHeight(), mCarrierLabelHeight));
+                    mPile.getHeight(), mNotificationScroller.getHeight(), mCarrierLabelHeight));
         }
 
         final boolean emergencyCallsShownElsewhere = mEmergencyCallLabel != null;
         final boolean makeVisible =
             !(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly())
             && mPile.getHeight() < (mNotificationPanel.getHeight() - mCarrierLabelHeight - mNotificationHeaderHeight)
-            && mScrollView.getVisibility() == View.VISIBLE;
+            && mNotificationScroller.getVisibility() == View.VISIBLE;
 
         if (force || mCarrierLabelVisible != makeVisible) {
             mCarrierLabelVisible = makeVisible;
@@ -1222,7 +1229,7 @@
         if (mHasFlipSettings
                 && mFlipSettingsView != null
                 && mFlipSettingsView.getVisibility() == View.VISIBLE
-                && mScrollView.getVisibility() != View.VISIBLE) {
+                && mNotificationScroller.getVisibility() != View.VISIBLE) {
             // the flip settings panel is unequivocally showing; we should not be shown
             mClearButton.setVisibility(View.INVISIBLE);
         } else if (mClearButton.isShown()) {
@@ -1476,7 +1483,7 @@
         }
 
         mExpandedVisible = true;
-        if(!ENABLE_NOTIFICATION_STACK) {
+        if (!ENABLE_NOTIFICATION_STACK) {
             ((NotificationRowLayout) mPile).setLayoutTransitionsEnabled(true);
         }
         if (mNavigationBarView != null)
@@ -1593,7 +1600,7 @@
         }
 
         mNotificationPanel.expand();
-        if (mHasFlipSettings && mScrollView.getVisibility() != View.VISIBLE) {
+        if (mHasFlipSettings && mNotificationScroller.getVisibility() != View.VISIBLE) {
             flipToNotifications();
         }
 
@@ -1607,11 +1614,11 @@
         if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
         if (mClearButtonAnim != null) mClearButtonAnim.cancel();
 
-        mScrollView.setVisibility(View.VISIBLE);
+        mNotificationScroller.setVisibility(View.VISIBLE);
         mScrollViewAnim = start(
             startDelay(FLIP_DURATION_OUT,
                 interpolator(mDecelerateInterpolator,
-                    ObjectAnimator.ofFloat(mScrollView, View.SCALE_X, 0f, 1f)
+                    ObjectAnimator.ofFloat(mNotificationScroller, View.SCALE_X, 0f, 1f)
                         .setDuration(FLIP_DURATION_IN)
                     )));
         mFlipSettingsViewAnim = start(
@@ -1669,8 +1676,8 @@
         mFlipSettingsView.setScaleX(1f);
         mFlipSettingsView.setVisibility(View.VISIBLE);
         mSettingsButton.setVisibility(View.GONE);
-        mScrollView.setVisibility(View.GONE);
-        mScrollView.setScaleX(0f);
+        mNotificationScroller.setVisibility(View.GONE);
+        mNotificationScroller.setScaleX(0f);
         mNotificationButton.setVisibility(View.VISIBLE);
         mNotificationButton.setAlpha(1f);
         mClearButton.setVisibility(View.GONE);
@@ -1697,15 +1704,15 @@
         mScrollViewAnim = start(
             setVisibilityWhenDone(
                 interpolator(mAccelerateInterpolator,
-                        ObjectAnimator.ofFloat(mScrollView, View.SCALE_X, 1f, 0f)
+                        ObjectAnimator.ofFloat(mNotificationScroller, View.SCALE_X, 1f, 0f)
                         )
                     .setDuration(FLIP_DURATION_OUT),
-                mScrollView, View.INVISIBLE));
+                    mNotificationScroller, View.INVISIBLE));
         mSettingsButtonAnim = start(
             setVisibilityWhenDone(
                 ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f)
                     .setDuration(FLIP_DURATION),
-                    mScrollView, View.INVISIBLE));
+                    mNotificationScroller, View.INVISIBLE));
         mNotificationButton.setVisibility(View.VISIBLE);
         mNotificationButtonAnim = start(
             ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f)
@@ -1759,8 +1766,8 @@
             if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
             if (mClearButtonAnim != null) mClearButtonAnim.cancel();
 
-            mScrollView.setScaleX(1f);
-            mScrollView.setVisibility(View.VISIBLE);
+            mNotificationScroller.setScaleX(1f);
+            mNotificationScroller.setVisibility(View.VISIBLE);
             mSettingsButton.setAlpha(1f);
             mSettingsButton.setVisibility(View.VISIBLE);
             mNotificationPanel.setVisibility(View.GONE);
@@ -1770,7 +1777,7 @@
         }
 
         mExpandedVisible = false;
-        if(!ENABLE_NOTIFICATION_STACK) {
+        if (!ENABLE_NOTIFICATION_STACK) {
             ((NotificationRowLayout) mPile).setLayoutTransitionsEnabled(false);
         }
         if (mNavigationBarView != null)
@@ -2143,7 +2150,7 @@
         if (!isDeviceProvisioned()) return;
 
         // not for you
-        if (!notificationIsForCurrentOrRelatedUser(n)) return;
+        if (!notificationIsForCurrentProfiles(n)) return;
 
         // Show the ticker if one is requested. Also don't do this
         // until status bar window is attached to the window manager,
@@ -2225,8 +2232,9 @@
             pw.println("  mDisplayMetrics=" + mDisplayMetrics);
             pw.println("  mPile: " + viewInfo(mPile));
             pw.println("  mTickerView: " + viewInfo(mTickerView));
-            pw.println("  mScrollView: " + viewInfo(mScrollView)
-                    + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY());
+            pw.println("  mNotificationScroller: " + viewInfo(mNotificationScroller)
+                    + " scroll " + mNotificationScroller.getScrollX()
+                    + "," + mNotificationScroller.getScrollY());
         }
 
         pw.print("  mInteractingWindows="); pw.println(mInteractingWindows);
@@ -2420,17 +2428,38 @@
 
     private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
         public void onClick(View v) {
+            // TODO: Handle this better with notification stack scroller
             synchronized (mNotificationData) {
+                mPostCollapseCleanup = new Runnable() {
+                    @Override
+                    public void run() {
+                        if (DEBUG) {
+                            Log.v(TAG, "running post-collapse cleanup");
+                        }
+                        try {
+                            if (!ENABLE_NOTIFICATION_STACK) {
+                                ((NotificationRowLayout) mPile).setViewRemoval(true);
+                            }
+                            mBarService.onClearAllNotifications(mCurrentUserId);
+                        } catch (Exception ex) { }
+                    }
+                };
+
+                if(ENABLE_NOTIFICATION_STACK) {
+                    animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+                    return;
+                }
+
                 // animate-swipe all dismissable notifications, then animate the shade closed
                 int numChildren = mPile.getChildCount();
 
-                int scrollTop = mScrollView.getScrollY();
-                int scrollBottom = scrollTop + mScrollView.getHeight();
+                int scrollTop = mNotificationScroller.getScrollY();
+                int scrollBottom = scrollTop + mNotificationScroller.getHeight();
                 final ArrayList<View> snapshot = new ArrayList<View>(numChildren);
                 for (int i=0; i<numChildren; i++) {
                     final View child = mPile.getChildAt(i);
-                    if (((SwipeHelper.Callback) mPile).canChildBeDismissed(child) && child.getBottom() > scrollTop &&
-                            child.getTop() < scrollBottom) {
+                    if (((SwipeHelper.Callback) mPile).canChildBeDismissed(child)
+                            && child.getBottom() > scrollTop && child.getTop() < scrollBottom) {
                         snapshot.add(child);
                     }
                 }
@@ -2448,28 +2477,13 @@
                         int totalDelay = 0;
 
 
-                        if(!ENABLE_NOTIFICATION_STACK) {
+                        if (!ENABLE_NOTIFICATION_STACK) {
                             // Set the shade-animating state to avoid doing other work during
                             // all of these animations. In particular, avoid layout and
                             // redrawing when collapsing the shade.
                             ((NotificationRowLayout) mPile).setViewRemoval(false);
                         }
 
-                        mPostCollapseCleanup = new Runnable() {
-                            @Override
-                            public void run() {
-                                if (DEBUG) {
-                                    Log.v(TAG, "running post-collapse cleanup");
-                                }
-                                try {
-                                    if (!ENABLE_NOTIFICATION_STACK) {
-                                        ((NotificationRowLayout) mPile).setViewRemoval(true);
-                                    }
-                                    mBarService.onClearAllNotifications(mCurrentUserId);
-                                } catch (Exception ex) { }
-                            }
-                        };
-
                         View sampleView = snapshot.get(0);
                         int width = sampleView.getWidth();
                         final int dir = sampleView.isLayoutRtl() ? -1 : +1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index aed9a71..d67f7cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -911,6 +911,7 @@
                 d.getWindow().setAttributes(lp);
             }
         };
+        v.setAutoActivate(true);
         v.setAdapter(new ZenModeViewAdapter(mContext) {
             @Override
             public void configure() {
@@ -928,7 +929,6 @@
         d.create();
         d.getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
         WindowManager.LayoutParams lp = d.getWindow().getAttributes();
-        lp.horizontalMargin = 0;
         lp.width = mContext.getResources().getDimensionPixelSize(R.dimen.zen_mode_dialog_width);
         d.getWindow().setAttributes(lp);
         d.show();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 925e0d8..eeae081 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -27,11 +27,11 @@
 import android.view.ViewGroup;
 import android.view.ViewRootImpl;
 import android.widget.FrameLayout;
-import android.widget.ScrollView;
 
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 
 public class StatusBarWindowView extends FrameLayout
@@ -42,7 +42,7 @@
     private ExpandHelper mExpandHelper;
     private ViewGroup latestItems;
     private NotificationPanelView mNotificationPanel;
-    private ScrollView mScrollView;
+    private View mNotificationScroller;
 
     PhoneStatusBar mService;
 
@@ -56,19 +56,37 @@
     protected void onAttachedToWindow () {
         super.onAttachedToWindow();
 
+        ExpandHelper.ScrollAdapter scrollAdapter;
         if (BaseStatusBar.ENABLE_NOTIFICATION_STACK) {
-            latestItems = (ViewGroup) findViewById(R.id.notification_stack_scroller);
+            NotificationStackScrollLayout stackScrollLayout =
+                    (NotificationStackScrollLayout) findViewById(R.id.notification_stack_scroller);
+
+            // ScrollView and notification container are unified in a single view now.
+            latestItems = stackScrollLayout;
+            scrollAdapter = stackScrollLayout;
+            mNotificationScroller = stackScrollLayout;
         } else {
             latestItems = (ViewGroup) findViewById(R.id.latestItems);
+            mNotificationScroller = findViewById(R.id.scroll);
+            scrollAdapter = new ExpandHelper.ScrollAdapter() {
+                @Override
+                public boolean isScrolledToTop() {
+                    return mNotificationScroller.getScrollY() == 0;
+                }
+
+                @Override
+                public View getHostView() {
+                    return mNotificationScroller;
+                }
+            };
         }
-        mScrollView = (ScrollView) findViewById(R.id.scroll);
         mNotificationPanel = (NotificationPanelView) findViewById(R.id.notification_panel);
         int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
         int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height);
         mExpandHelper = new ExpandHelper(getContext(), (ExpandHelper.Callback) latestItems,
                 minHeight, maxHeight);
         mExpandHelper.setEventSource(this);
-        mExpandHelper.setScrollView(mScrollView);
+        mExpandHelper.setScrollAdapter(scrollAdapter);
 
         // We really need to be able to animate while window animations are going on
         // so that activities may be started asynchronously from panel animations
@@ -94,7 +112,8 @@
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         boolean intercept = false;
-        if (mNotificationPanel.isFullyExpanded() && mScrollView.getVisibility() == View.VISIBLE) {
+        if (mNotificationPanel.isFullyExpanded()
+                && mNotificationScroller.getVisibility() == View.VISIBLE) {
             intercept = mExpandHelper.onInterceptTouchEvent(ev);
         }
         if (!intercept) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
index d1a9d57..49cf78b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
@@ -16,11 +16,8 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.content.Context;
-import android.graphics.Paint;
 import android.graphics.PorterDuff.Mode;
 import android.graphics.Typeface;
 import android.graphics.drawable.ShapeDrawable;
@@ -39,14 +36,12 @@
 import android.widget.CompoundButton;
 import android.widget.CompoundButton.OnCheckedChangeListener;
 import android.widget.FrameLayout;
-import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.RelativeLayout;
 import android.widget.Switch;
 import android.widget.TextView;
 import android.widget.Toast;
 
-import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.ZenModeView.Adapter.ExitCondition;
 
 public class ZenModeView extends RelativeLayout {
@@ -63,20 +58,21 @@
 
     private static final long DURATION = new ValueAnimator().getDuration();
     private static final long PAGER_DURATION = DURATION / 2;
-    private static final float BOUNCE_SCALE = 0.8f;
     private static final long CLOSE_DELAY = 600;
+    private static final long AUTO_ACTIVATE_DELAY = 100;
 
     private final Context mContext;
-    private final Paint mPathPaint;
-    private final ImageView mSettingsButton;
     private final TextView mModeText;
     private final Switch mModeSwitch;
     private final View mDivider;
     private final UntilPager mUntilPager;
     private final ProgressDots mProgressDots;
+    private final View mDivider2;
+    private final TextView mSettingsButton;
 
     private Adapter mAdapter;
     private boolean mInit;
+    private boolean mAutoActivate;
 
     public ZenModeView(Context context) {
         this(context, null);
@@ -90,29 +86,9 @@
         final int iconSize = mContext.getResources()
                 .getDimensionPixelSize(com.android.internal.R.dimen.notification_large_icon_width);
         final int topRowSize = iconSize * 2 / 3;
-        final int p = topRowSize / 7;
+        final int p = topRowSize / 3;
 
-        mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mPathPaint.setStyle(Paint.Style.STROKE);
-        mPathPaint.setColor(GRAY);
-        mPathPaint.setStrokeWidth(p / 2);
-
-        mSettingsButton = new ImageView(mContext);
-        mSettingsButton.setPadding(p, p, p, p);
-        mSettingsButton.setImageResource(R.drawable.ic_notify_settings_normal);
-        LayoutParams lp = new LayoutParams(topRowSize, topRowSize);
-        lp.topMargin = p;
-        lp.leftMargin = p;
-        addView(mSettingsButton, lp);
-        mSettingsButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                if (mAdapter != null) {
-                    mAdapter.configure();
-                }
-                bounce(mSettingsButton, null);
-            }
-        });
+        LayoutParams lp = null;
 
         mModeText = new TextView(mContext);
         mModeText.setText(MODE_LABEL);
@@ -120,11 +96,10 @@
         mModeText.setTextColor(GRAY);
         mModeText.setTypeface(CONDENSED);
         mModeText.setAllCaps(true);
-        mModeText.setGravity(Gravity.CENTER);
-        mModeText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mModeText.getTextSize() * 1.1f);
+        mModeText.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
+        mModeText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mModeText.getTextSize() * 1.5f);
         lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize);
-        lp.topMargin = p;
-        lp.addRule(CENTER_HORIZONTAL);
+        lp.leftMargin = p;
         addView(mModeText, lp);
 
         mModeSwitch = new Switch(mContext);
@@ -132,6 +107,7 @@
         mModeSwitch.setSwitchTypeface(CONDENSED);
         lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize);
         lp.topMargin = p;
+        lp.rightMargin = p;
         lp.addRule(ALIGN_PARENT_RIGHT);
         lp.addRule(ALIGN_BASELINE, mModeText.getId());
         addView(mModeSwitch, lp);
@@ -154,11 +130,10 @@
         mDivider.setBackgroundColor(GRAY);
         lp = new LayoutParams(LayoutParams.MATCH_PARENT, 2);
         lp.addRule(BELOW, mModeText.getId());
-        lp.topMargin = p;
-        lp.bottomMargin = p * 2;
+        lp.bottomMargin = p;
         addView(mDivider, lp);
 
-        mUntilPager = new UntilPager(mContext, mPathPaint, iconSize * 3 / 4);
+        mUntilPager = new UntilPager(mContext, iconSize * 3 / 4);
         mUntilPager.setId(android.R.id.tabhost);
         lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
         lp.leftMargin = lp.rightMargin = iconSize / 2;
@@ -167,10 +142,41 @@
         addView(mUntilPager, lp);
 
         mProgressDots = new ProgressDots(mContext, iconSize / 5);
+        mProgressDots.setId(android.R.id.progress);
         lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
         lp.addRule(CENTER_HORIZONTAL);
         lp.addRule(BELOW, mUntilPager.getId());
         addView(mProgressDots, lp);
+
+        mDivider2 = new View(mContext);
+        mDivider2.setId(android.R.id.widget_frame);
+        mDivider2.setBackgroundColor(GRAY);
+        lp = new LayoutParams(LayoutParams.MATCH_PARENT, 2);
+        lp.addRule(BELOW, mProgressDots.getId());
+        addView(mDivider2, lp);
+
+        mSettingsButton = new TextView(mContext);
+        mSettingsButton.setTypeface(CONDENSED);
+        mSettingsButton.setTextSize(TypedValue.COMPLEX_UNIT_PX, mSettingsButton.getTextSize() * 1.3f);
+        mSettingsButton.setPadding(p, p, p, p);
+        mSettingsButton.setText("More settings...");
+        lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+        lp.addRule(BELOW, mDivider2.getId());
+        addView(mSettingsButton, lp);
+        mSettingsButton.setOnTouchListener(new OnTouchListener() {
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                if (event.getAction() == MotionEvent.ACTION_DOWN) {
+                    mSettingsButton.setBackgroundColor(DARK_GRAY);
+                } else if (event.getAction() == MotionEvent.ACTION_UP) {
+                    mSettingsButton.setBackground(null);
+                    if (mAdapter != null) {
+                        mAdapter.configure();
+                    }
+                }
+                return true;
+            }
+        });
     }
 
     public void setAdapter(Adapter adapter) {
@@ -189,6 +195,27 @@
         updateState(false);
     }
 
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        if (mAutoActivate) {
+            mAutoActivate = false;
+            postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    if (!mModeSwitch.isChecked()) {
+                        mInit = false;
+                        mModeSwitch.setChecked(true);
+                    }
+                }
+            }, AUTO_ACTIVATE_DELAY);
+        }
+    }
+
+    public void setAutoActivate(boolean value) {
+        mAutoActivate = value;
+    }
+
     private void updateState(boolean animate) {
         mUntilPager.updateState();
         mModeSwitch.setChecked(mAdapter.getMode());
@@ -199,23 +226,6 @@
         Log.d(TAG, args == null || args.length == 0 ? msg : String.format(msg, args));
     }
 
-    private static void bounce(final View v, final Runnable midBounce) {
-        v.animate().scaleX(BOUNCE_SCALE).scaleY(BOUNCE_SCALE).setDuration(DURATION / 3)
-            .setListener(new AnimatorListenerAdapter() {
-                private boolean mFired;
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    if (!mFired) {
-                        mFired = true;
-                        if (midBounce != null) {
-                            midBounce.run();
-                        }
-                        v.animate().scaleX(1).scaleY(1).setListener(null).start();
-                    }
-                }
-            }).start();
-    }
-
     private final class UntilView extends FrameLayout {
         private static final boolean SUPPORT_LINKS = false;
 
@@ -223,7 +233,7 @@
         public UntilView(Context context) {
             super(context);
             mText = new TextView(mContext);
-            mText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mText.getTextSize() * 1.2f);
+            mText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mText.getTextSize() * 1.3f);
             mText.setTypeface(CONDENSED);
             mText.setTextColor(GRAY);
             mText.setGravity(Gravity.CENTER);
@@ -284,7 +294,7 @@
         private int mCurrent;
         private float mDownX;
 
-        public UntilPager(Context context, Paint pathPaint, int iconSize) {
+        public UntilPager(Context context, int iconSize) {
             super(context);
             mViews = new UntilView[3];
             for (int i = 0; i < mViews.length; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index edac3a7..f6eeb6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -22,6 +22,7 @@
 import android.graphics.Canvas;
 import android.graphics.Outline;
 import android.graphics.Paint;
+
 import android.util.AttributeSet;
 import android.util.Log;
 
@@ -37,12 +38,13 @@
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
 
 /**
  * A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
  */
 public class NotificationStackScrollLayout extends ViewGroup
-        implements SwipeHelper.Callback, ExpandHelper.Callback {
+        implements SwipeHelper.Callback, ExpandHelper.Callback, ExpandHelper.ScrollAdapter {
 
     private static final String TAG = "NotificationStackScrollLayout";
     private static final boolean DEBUG = false;
@@ -86,7 +88,9 @@
     /**
      * The current State this Layout is in
      */
-    private StackScrollState mCurrentStackScrollState;
+    private final StackScrollState mCurrentStackScrollState = new StackScrollState(this);
+
+    private OnChildLocationsChangedListener mListener;
 
     public NotificationStackScrollLayout(Context context) {
         this(context, null);
@@ -153,7 +157,6 @@
         // currently the padding is in the elements themself
         mPaddingBetweenElements = 0;
         mStackScrollAlgorithm = new StackScrollAlgorithm(context);
-        mCurrentStackScrollState = null;
     }
 
     @Override
@@ -188,6 +191,24 @@
         updateContentHeight();
     }
 
+    public void setChildLocationsChangedListener(OnChildLocationsChangedListener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Returns the location the given child is currently rendered at.
+     *
+     * @param child the child to get the location for
+     * @return one of {@link ViewState}'s <code>LOCATION_*</code> constants
+     */
+    public int getChildLocation(View child) {
+        ViewState childViewState = mCurrentStackScrollState.getViewStateForView(child);
+        if (childViewState == null) {
+            return ViewState.LOCATION_UNKNOWN;
+        }
+        return childViewState.location;
+    }
+
     private void setMaxLayoutHeight(int maxLayoutHeight) {
         mMaxLayoutHeight = maxLayoutHeight;
         updateAlgorithmHeight();
@@ -203,13 +224,13 @@
      */
     private void updateChildren() {
         if (!isCurrentlyAnimating()) {
-            if (mCurrentStackScrollState == null) {
-                mCurrentStackScrollState = new StackScrollState(this);
-            }
             mCurrentStackScrollState.setScrollY(mOwnScrollY);
             mStackScrollAlgorithm.getStackScrollState(mCurrentStackScrollState);
             mCurrentStackScrollState.apply();
             mOwnScrollY = mCurrentStackScrollState.getScrollY();
+            if (mListener != null) {
+                mListener.onChildLocationsChanged(this);
+            }
         } else {
             // TODO: handle animation
         }
@@ -813,4 +834,21 @@
             mSwipeHelper.removeLongPressCallback();
         }
     }
+
+    @Override
+    public boolean isScrolledToTop() {
+        return mOwnScrollY == 0;
+    }
+
+    @Override
+    public View getHostView() {
+        return this;
+    }
+
+    /**
+     * A listener that is notified when some child locations might have changed.
+     */
+    public interface OnChildLocationsChangedListener {
+        public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 9db4e77..6d2ba6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.stack;
 
 import android.content.Context;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import com.android.systemui.R;
@@ -28,6 +29,8 @@
  */
 public class StackScrollAlgorithm {
 
+    private static final String LOG_TAG = "StackScrollAlgorithm";
+
     private static final int MAX_ITEMS_IN_BOTTOM_STACK = 3;
     private static final int MAX_ITEMS_IN_TOP_STACK = 3;
 
@@ -130,6 +133,7 @@
             View child = hostView.getChildAt(i);
             StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
             childViewState.yTranslation = currentYPosition;
+            childViewState.location = StackScrollState.ViewState.LOCATION_UNKNOWN;
             int childHeight = child.getHeight();
             // The y position after this element
             float nextYPosition = currentYPosition + childHeight + mPaddingBetweenElements;
@@ -143,12 +147,12 @@
                 nextYPosition = updateStateForTopStackChild(algorithmState,
                         numberOfElementsCompletelyIn,
                         i, childViewState);
-
             } else if (i == algorithmState.lastTopStackIndex) {
                 // Case 2:
                 // First element of regular scrollview comes next, so the position is just the
                 // scrolling position
                 nextYPosition = scrollOffset;
+                childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING;
             } else if (nextYPosition >= transitioningPositionStart) {
                 if (currentYPosition >= transitioningPositionStart) {
                     // Case 3:
@@ -156,8 +160,6 @@
                     // bottom of the screen so we are fully in the bottom stack
                     nextYPosition = updateStateForChildFullyInBottomStack(algorithmState,
                             transitioningPositionStart, childViewState, childHeight);
-
-
                 } else {
                     // Case 4:
                     // According to the regular scroll view we are currently translating out of /
@@ -167,6 +169,16 @@
                             currentYPosition, childViewState,
                             childHeight, nextYPosition);
                 }
+            } else {
+                childViewState.location = StackScrollState.ViewState.LOCATION_MAIN_AREA;
+            }
+            // The first card is always rendered.
+            if (i == 0) {
+                childViewState.alpha = 1.0f;
+                childViewState.location = StackScrollState.ViewState.LOCATION_FIRST_CARD;
+            }
+            if (childViewState.location == StackScrollState.ViewState.LOCATION_UNKNOWN) {
+                Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
             }
             currentYPosition = nextYPosition;
             yPositionInScrollView = yPositionInScrollViewAfterElement;
@@ -192,6 +204,8 @@
         if (childHeight != (int) newSize) {
             childViewState.height = (int) newSize;
         }
+        childViewState.location = StackScrollState.ViewState.LOCATION_MAIN_AREA;
+
         return nextYPosition;
     }
 
@@ -206,6 +220,7 @@
             nextYPosition = transitioningPositionStart
                     + mBottomStackIndentationFunctor.getValue(
                             algorithmState.itemsInBottomStack);
+            childViewState.location = StackScrollState.ViewState.LOCATION_BOTTOM_STACK_PEEKING;
         } else {
             // we are fully inside the stack
             if (algorithmState.itemsInBottomStack > MAX_ITEMS_IN_BOTTOM_STACK + 2) {
@@ -214,6 +229,7 @@
                     > MAX_ITEMS_IN_BOTTOM_STACK + 1) {
                 childViewState.alpha = 1.0f - algorithmState.partialInBottom;
             }
+            childViewState.location = StackScrollState.ViewState.LOCATION_BOTTOM_STACK_HIDDEN;
             nextYPosition = transitioningPositionStart + mBottomStackPeekSize;
         }
         // TODO: only temporarily collapse
@@ -237,14 +253,16 @@
             nextYPosition = mCollapsedSize + mPaddingBetweenElements -
                     mTopStackIndentationFunctor.getValue(
                             algorithmState.itemsInTopStack - i - 1);
-            if (paddedIndex == 0 && i != 0) {
+            if (paddedIndex == 0) {
                 childViewState.alpha = 1.0f - algorithmState.partialInTop;
+                childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_HIDDEN;
+            } else {
+                childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING;
             }
         } else {
-            // We are hidden behind the top card and faded out, so we can hide ourselfs
-            if (i != 0) {
-                childViewState.alpha = 0.0f;
-            }
+            // We are hidden behind the top card and faded out, so we can hide ourselves.
+            childViewState.alpha = 0.0f;
+            childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_HIDDEN;
         }
         return nextYPosition;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index f72a52f..881730a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -45,7 +45,7 @@
 
     public StackScrollState(ViewGroup hostView) {
         mHostView = hostView;
-        mStateMap = new HashMap<View, ViewState>(mHostView.getChildCount());
+        mStateMap = new HashMap<View, ViewState>();
     }
 
     public ViewGroup getHostView() {
@@ -144,10 +144,28 @@
     }
 
 
-    public class ViewState {
+    public static class ViewState {
+
+        // These are flags such that we can create masks for filtering.
+
+        public static final int LOCATION_UNKNOWN = 0x00;
+        public static final int LOCATION_FIRST_CARD = 0x01;
+        public static final int LOCATION_TOP_STACK_HIDDEN = 0x02;
+        public static final int LOCATION_TOP_STACK_PEEKING = 0x04;
+        public static final int LOCATION_MAIN_AREA = 0x08;
+        public static final int LOCATION_BOTTOM_STACK_PEEKING = 0x10;
+        public static final int LOCATION_BOTTOM_STACK_HIDDEN = 0x20;
+
         float alpha;
         float yTranslation;
         float zTranslation;
         int height;
+
+        /**
+         * The location this view is currently rendered at.
+         *
+         * <p>See <code>LOCATION_</code> flags.</p>
+         */
+        int location;
     }
 }
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
index fb002d2..5c8a8ef8 100644
--- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
@@ -365,12 +365,6 @@
 
         Point inSize = mCropView.getSourceDimensions();
 
-        // Due to rounding errors in the cropview renderer the edges can be slightly offset
-        // therefore we ensure that the boundaries are sanely defined
-        cropRect.left = Math.max(0, cropRect.left);
-        cropRect.right = Math.min(inSize.x, cropRect.right);
-        cropRect.top = Math.max(0, cropRect.top);
-        cropRect.bottom = Math.min(inSize.y, cropRect.bottom);
         int cropRotation = mCropView.getImageRotation();
         float cropScale = mCropView.getWidth() / (float) cropRect.width();
 
@@ -381,6 +375,13 @@
         rotatedInSize[0] = Math.abs(rotatedInSize[0]);
         rotatedInSize[1] = Math.abs(rotatedInSize[1]);
 
+        // Due to rounding errors in the cropview renderer the edges can be slightly offset
+        // therefore we ensure that the boundaries are sanely defined
+        cropRect.left = Math.max(0, cropRect.left);
+        cropRect.right = Math.min(rotatedInSize[0], cropRect.right);
+        cropRect.top = Math.max(0, cropRect.top);
+        cropRect.bottom = Math.min(rotatedInSize[1], cropRect.bottom);
+
         // ADJUST CROP WIDTH
         // Extend the crop all the way to the right, for parallax
         // (or all the way to the left, in RTL)
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index 0120a03..6e025bb 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -121,13 +121,14 @@
         filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
         context.registerReceiver(mBroadcastReceiver, filter);
 
+        ConnectivityManager cm = (ConnectivityManager)
+                context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mHasTelephony = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+
         // get notified of phone state changes
         TelephonyManager telephonyManager =
                 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
         telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
-        ConnectivityManager cm = (ConnectivityManager)
-                context.getSystemService(Context.CONNECTIVITY_SERVICE);
-        mHasTelephony = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
                 mAirplaneModeObserver);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index a65f677..f1db904 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -145,6 +145,7 @@
     TypedValue mFixedWidthMinor;
     TypedValue mFixedHeightMajor;
     TypedValue mFixedHeightMinor;
+    TypedValue mOutsetBottom;
 
     // This is the top-level view of the window, containing the window decor.
     private DecorView mDecor;
@@ -2370,7 +2371,6 @@
                     } else {
                         h = 0;
                     }
-
                     if (h > 0) {
                         final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
                         heightMeasureSpec = MeasureSpec.makeMeasureSpec(
@@ -2379,6 +2379,15 @@
                 }
             }
 
+            if (mOutsetBottom != null) {
+                int mode = MeasureSpec.getMode(heightMeasureSpec);
+                if (mode != MeasureSpec.UNSPECIFIED) {
+                    int outset = (int) mOutsetBottom.getDimension(metrics);
+                    int height = MeasureSpec.getSize(heightMeasureSpec);
+                    heightMeasureSpec = MeasureSpec.makeMeasureSpec(height + outset, mode);
+                }
+            }
+
             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
             int width = getMeasuredWidth();
@@ -2993,6 +3002,10 @@
         if (a.getBoolean(com.android.internal.R.styleable.Window_windowContentTransitions, false)) {
             requestFeature(FEATURE_CONTENT_TRANSITIONS);
         }
+        if (a.hasValue(com.android.internal.R.styleable.Window_windowOutsetBottom)) {
+            if (mOutsetBottom == null) mOutsetBottom = new TypedValue();
+            a.getValue(com.android.internal.R.styleable.Window_windowOutsetBottom, mOutsetBottom);
+        }
 
         final Context context = getContext();
         final int targetSdk = context.getApplicationInfo().targetSdkVersion;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ededbb2..ccdacea 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -3417,8 +3417,9 @@
             }
 
             final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0;
+            final boolean dismissKeyguard = (fl & FLAG_DISMISS_KEYGUARD) != 0;
             if (appWindow) {
-                if (showWhenLocked) {
+                if (showWhenLocked || (dismissKeyguard && !isKeyguardSecure())) {
                     mAppsToBeHidden.remove(win.getAppToken());
                 } else {
                     mAppsToBeHidden.add(win.getAppToken());
@@ -3435,8 +3436,7 @@
                             mHideLockScreen = true;
                             mForceStatusBarFromKeyguard = false;
                         }
-                        if ((fl & FLAG_DISMISS_KEYGUARD) != 0
-                                && mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
+                        if (dismissKeyguard && mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
                             if (DEBUG_LAYOUT) Slog.v(TAG,
                                     "Setting mDismissKeyguard true by win " + win);
                             mDismissKeyguard = mWinDismissingKeyguard == win ?
diff --git a/rs/java/android/renderscript/RenderScriptGL.java b/rs/java/android/renderscript/RenderScriptGL.java
index 714e835..6178994 100644
--- a/rs/java/android/renderscript/RenderScriptGL.java
+++ b/rs/java/android/renderscript/RenderScriptGL.java
@@ -225,9 +225,13 @@
         validate();
         //android.util.Log.v("rs", "set surface " + sur + " w=" + w + ", h=" + h);
 
+        Surface s = null;
+        if (sur != null) {
+            s = new Surface(sur);
+        }
         mWidth = w;
         mHeight = h;
-        nContextSetSurfaceTexture(w, h, sur);
+        nContextSetSurface(w, h, s);
     }
 
     /**
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index b7c1704..2f56e62 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -1751,7 +1751,8 @@
                 for (int i = 0; i < N; i++) {
                     AppWidgetId id = mAppWidgetIds.get(i);
                     if (backupTarget.equals(id.host.packageName)
-                            || backupTarget.equals(id.provider.info.provider.getPackageName())) {
+                            || (id.provider != null && backupTarget.equals(
+                                    id.provider.info.provider.getPackageName()))) {
                         serializeAppWidgetId(out, id);
                     }
                 }
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 1a1512f..57c2f92 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -2035,6 +2035,7 @@
         BackupState mCurrentState;
 
         // carried information about the current in-flight operation
+        IBackupAgent mAgentBinder;
         PackageInfo mCurrentPackage;
         File mSavedStateName;
         File mBackupDataName;
@@ -2097,6 +2098,7 @@
                 addBackupTrace(b.toString());
             }
 
+            mAgentBinder = null;
             mStatus = BackupConstants.TRANSPORT_OK;
 
             // Sanity check: if the queue is empty we have no work to do.
@@ -2228,6 +2230,7 @@
                             IApplicationThread.BACKUP_MODE_INCREMENTAL);
                     addBackupTrace("agent bound; a? = " + (agent != null));
                     if (agent != null) {
+                        mAgentBinder = agent;
                         mStatus = invokeAgentForBackup(request.packageName, agent, mTransport);
                         // at this point we'll either get a completion callback from the
                         // agent, or a timeout message on the main handler.  either way, we're
@@ -2253,6 +2256,7 @@
                 // That means we need to direct to the next state ourselves.
                 if (mStatus != BackupConstants.TRANSPORT_OK) {
                     BackupState nextState = BackupState.RUNNING_QUEUE;
+                    mAgentBinder = null;
 
                     // An agent-level failure means we reenqueue this one agent for
                     // a later retry, but otherwise proceed normally.
@@ -2274,6 +2278,7 @@
 
                     executeNextState(nextState);
                 } else {
+                    // success case
                     addBackupTrace("expecting completion/timeout callback");
                 }
             }
@@ -2402,14 +2407,52 @@
             return BackupConstants.TRANSPORT_OK;
         }
 
+        public void failAgent(IBackupAgent agent, String message) {
+            try {
+                agent.fail(message);
+            } catch (Exception e) {
+                Slog.w(TAG, "Error conveying failure to " + mCurrentPackage.packageName);
+            }
+        }
+
         @Override
         public void operationComplete() {
-            // Okay, the agent successfully reported back to us.  The next thing we do is
-            // push the app widget state for the app, if any.
+            // Okay, the agent successfully reported back to us!
             final String pkgName = mCurrentPackage.packageName;
             final long filepos = mBackupDataName.length();
             FileDescriptor fd = mBackupData.getFileDescriptor();
             try {
+                // If it's a 3rd party app, see whether they wrote any protected keys
+                // and complain mightily if they are attempting shenanigans.
+                if (mCurrentPackage.applicationInfo != null &&
+                        (mCurrentPackage.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+                    ParcelFileDescriptor readFd = ParcelFileDescriptor.open(mBackupDataName,
+                            ParcelFileDescriptor.MODE_READ_ONLY);
+                    BackupDataInput in = new BackupDataInput(readFd.getFileDescriptor());
+                    try {
+                        while (in.readNextHeader()) {
+                            final String key = in.getKey();
+                            if (key != null && key.charAt(0) >= 0xff00) {
+                                // Not okay: crash them and bail.
+                                failAgent(mAgentBinder, "Illegal backup key: " + key);
+                                addBackupTrace("illegal key " + key + " from " + pkgName);
+                                EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, pkgName,
+                                        "bad key");
+                                mBackupHandler.removeMessages(MSG_TIMEOUT);
+                                agentErrorCleanup();
+                                // agentErrorCleanup() implicitly executes next state properly
+                                return;
+                            }
+                            in.skipEntityData();
+                        }
+                    } finally {
+                        if (readFd != null) {
+                            readFd.close();
+                        }
+                    }
+                }
+
+                // Piggyback the widget state payload, if any
                 BackupDataOutput out = new BackupDataOutput(fd);
                 byte[] widgetState = AppWidgetBackupBridge.getWidgetState(pkgName,
                         UserHandle.USER_OWNER);
@@ -2434,8 +2477,7 @@
                 }
             }
 
-            // Spin the data off to the
-            // transport and proceed with the next stage.
+            // Spin the data off to the transport and proceed with the next stage.
             if (MORE_DEBUG) Slog.v(TAG, "operationComplete(): sending data to transport for "
                     + pkgName);
             mBackupHandler.removeMessages(MSG_TIMEOUT);
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 5fb6405..e69c9a4 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -445,7 +445,7 @@
                 return;
             } else if (Intent.ACTION_USER_ADDED.equals(action)
                     || Intent.ACTION_USER_REMOVED.equals(action)) {
-                updateRelatedUserIds();
+                updateCurrentProfileIds();
                 return;
             } else {
                 Slog.w(TAG, "Unexpected intent " + intent);
@@ -689,7 +689,7 @@
         // mSettings should be created before buildInputMethodListLocked
         mSettings = new InputMethodSettings(
                 mRes, context.getContentResolver(), mMethodMap, mMethodList, userId);
-        updateRelatedUserIds();
+        updateCurrentProfileIds();
         mFileManager = new InputMethodFileManager(mMethodMap, userId);
         mSwitchingController = new InputMethodSubtypeSwitchingController(mSettings);
         mSwitchingController.resetCircularListLocked(context);
@@ -805,7 +805,7 @@
 
     private void switchUserLocked(int newUserId) {
         mSettings.setCurrentUserId(newUserId);
-        updateRelatedUserIds();
+        updateCurrentProfileIds();
         // InputMethodFileManager should be reset when the user is changed
         mFileManager = new InputMethodFileManager(mMethodMap, newUserId);
         final String defaultImiId = mSettings.getSelectedInputMethod();
@@ -826,14 +826,14 @@
         }
     }
 
-    void updateRelatedUserIds() {
-        List<UserInfo> relatedUsers =
-                UserManager.get(mContext).getRelatedUsers(mSettings.getCurrentUserId());
-        int[] relatedUserIds = new int[relatedUsers.size()]; // relatedUsers will not be null
-        for (int i = 0; i < relatedUserIds.length; i++) {
-            relatedUserIds[i] = relatedUsers.get(i).id;
+    void updateCurrentProfileIds() {
+        List<UserInfo> profiles =
+                UserManager.get(mContext).getProfiles(mSettings.getCurrentUserId());
+        int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
+        for (int i = 0; i < currentProfileIds.length; i++) {
+            currentProfileIds[i] = profiles.get(i).id;
         }
-        mSettings.setRelatedUserIds(relatedUserIds);
+        mSettings.setCurrentProfileIds(currentProfileIds);
     }
 
     @Override
@@ -931,7 +931,7 @@
                     + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid()
                     + InputMethodUtils.getApiCallStack());
         }
-        if (uid == Process.SYSTEM_UID || mSettings.isRelatedToOrCurrentUser(userId)) {
+        if (uid == Process.SYSTEM_UID || mSettings.isCurrentProfile(userId)) {
             return true;
         }
 
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index fe814fc..0d2cee8 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -30,7 +30,11 @@
 import android.database.sqlite.SQLiteStatement;
 import android.os.Binder;
 import android.os.Environment;
+import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.storage.IMountService;
+import android.os.ServiceManager;
+import android.os.storage.StorageManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -79,6 +83,7 @@
 
     private final Context mContext;
     private LockPatternUtils mLockPatternUtils;
+    private boolean mFirstCallToVold;
 
     public LockSettingsService(Context context) {
         mContext = context;
@@ -86,6 +91,7 @@
         mOpenHelper = new DatabaseHelper(mContext);
 
         mLockPatternUtils = new LockPatternUtils(context);
+        mFirstCallToVold = true;
     }
 
     public void systemReady() {
@@ -347,6 +353,51 @@
     }
 
     @Override
+        public boolean checkVoldPassword(int userId) throws RemoteException {
+        if (!mFirstCallToVold) {
+            return false;
+        }
+        mFirstCallToVold = false;
+
+        checkPasswordReadPermission(userId);
+
+        // There's no guarantee that this will safely connect, but if it fails
+        // we will simply show the lock screen when we shouldn't, so relatively
+        // benign. There is an outside chance something nasty would happen if
+        // this service restarted before vold stales out the password in this
+        // case. The nastiness is limited to not showing the lock screen when
+        // we should, within the first minute of decrypting the phone if this
+        // service can't connect to vold, it restarts, and then the new instance
+        // does successfully connect.
+        final IMountService service = getMountService();
+        String password = service.getPassword();
+        service.clearPassword();
+        if (password == null) {
+            return false;
+        }
+
+        try {
+            if (mLockPatternUtils.isLockPatternEnabled()) {
+                if (checkPattern(password, userId)) {
+                    return true;
+                }
+            }
+        } catch (Exception e) {
+        }
+
+        try {
+            if (mLockPatternUtils.isLockPasswordEnabled()) {
+                if (checkPassword(password, userId)) {
+                    return true;
+                }
+            }
+        } catch (Exception e) {
+        }
+
+        return false;
+    }
+
+    @Override
     public void removeUser(int userId) {
         checkWritePermission(userId);
 
@@ -524,4 +575,12 @@
         Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
         Secure.LOCK_SCREEN_OWNER_INFO
     };
+
+    private IMountService getMountService() {
+        final IBinder service = ServiceManager.getService("mount");
+        if (service != null) {
+            return IMountService.Stub.asInterface(service);
+        }
+        return null;
+    }
 }
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index cd74fed..c1d9fbd 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -74,6 +74,7 @@
 import com.google.android.collect.Maps;
 
 import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.codec.DecoderException;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.File;
@@ -573,6 +574,14 @@
         }
     }
 
+    private boolean isReady() {
+        try {
+            return mConnectedSignal.await(0, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            return false;
+        }
+    }
+
     private void handleSystemReady() {
         // Snapshot current volume states since it's not safe to call into vold
         // while holding locks.
@@ -2075,12 +2084,25 @@
 
     private String toHex(String password) {
         if (password == null) {
-            return null;
+            return new String();
         }
         byte[] bytes = password.getBytes(StandardCharsets.UTF_8);
         return new String(Hex.encodeHex(bytes));
     }
 
+    private String fromHex(String hexPassword) {
+        if (hexPassword == null) {
+            return null;
+        }
+
+        try {
+            byte[] bytes = Hex.decodeHex(hexPassword.toCharArray());
+            return new String(bytes, StandardCharsets.UTF_8);
+        } catch (DecoderException e) {
+            return null;
+        }
+    }
+
     @Override
     public int decryptStorage(String password) {
         if (TextUtils.isEmpty(password)) {
@@ -2230,6 +2252,35 @@
     }
 
     @Override
+    public String getPassword() throws RemoteException {
+        if (!isReady()) {
+            return new String();
+        }
+
+        final NativeDaemonEvent event;
+        try {
+            event = mConnector.execute("cryptfs", "getpw");
+            return fromHex(event.getMessage());
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void clearPassword() throws RemoteException {
+        if (!isReady()) {
+            return;
+        }
+
+        final NativeDaemonEvent event;
+        try {
+            event = mConnector.execute("cryptfs", "clearpw");
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
     public int mkdirs(String callingPkg, String appPath) {
         final int userId = UserHandle.getUserId(Binder.getCallingUid());
         final UserEnvironment userEnv = new UserEnvironment(userId);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5fa9084..ac6f684 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -43,6 +43,7 @@
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.ProcessCpuTracker;
 import com.android.internal.os.TransferPipe;
+import com.android.internal.os.Zygote;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.MemInfoReader;
@@ -61,8 +62,6 @@
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
-import dalvik.system.Zygote;
-
 import libcore.io.IoUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -945,6 +944,11 @@
      */
     boolean mDidDexOpt;
 
+    /**
+     * Set if the systemServer made a call to enterSafeMode.
+     */
+    boolean mSafeMode;
+
     String mDebugApp = null;
     boolean mWaitForDebugger = false;
     boolean mDebugTransient = false;
@@ -1015,7 +1019,7 @@
     final ActivityThread mSystemThread;
 
     int mCurrentUserId = 0;
-    int[] mRelatedUserIds = new int[0]; // Accessed by ActivityStack
+    int[] mCurrentProfileIds = new int[0]; // Accessed by ActivityStack
     private UserManagerService mUserManager;
 
     private final class AppDeathRecipient implements IBinder.DeathRecipient {
@@ -1074,7 +1078,7 @@
     static final int IMMERSIVE_MODE_LOCK_MSG = 37;
     static final int PERSIST_URI_GRANTS_MSG = 38;
     static final int REQUEST_ALL_PSS_MSG = 39;
-    static final int START_RELATED_USERS_MSG = 40;
+    static final int START_PROFILES_MSG = 40;
     static final int UPDATE_TIME = 41;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
@@ -1689,9 +1693,9 @@
                 requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
                 break;
             }
-            case START_RELATED_USERS_MSG: {
+            case START_PROFILES_MSG: {
                 synchronized (ActivityManagerService.this) {
-                    startRelatedUsersLocked();
+                    startProfilesLocked();
                 }
                 break;
             }
@@ -2737,7 +2741,7 @@
             // Run the app in safe mode if its manifest requests so or the
             // system is booted in safe mode.
             if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
-                Zygote.systemInSafeMode == true) {
+                mSafeMode == true) {
                 debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
             }
             if ("1".equals(SystemProperties.get("debug.checkjni"))) {
@@ -5204,7 +5208,7 @@
                                 userId);
                     }
                 }
-                scheduleStartRelatedUsersLocked();
+                scheduleStartProfilesLocked();
             }
         }
     }
@@ -6859,8 +6863,8 @@
                             maxNum < N ? maxNum : N);
 
             final Set<Integer> includedUsers;
-            if ((flags & ActivityManager.RECENT_INCLUDE_RELATED) != 0) {
-                includedUsers = getRelatedUsersLocked(userId);
+            if ((flags & ActivityManager.RECENT_INCLUDE_PROFILES) != 0) {
+                includedUsers = getProfileIdsLocked(userId);
             } else {
                 includedUsers = new HashSet<Integer>();
             }
@@ -8963,6 +8967,8 @@
                 } catch (RemoteException e) {
                 }
             }
+
+            mSafeMode = true;
         }
     }
 
@@ -16311,19 +16317,19 @@
      * user switch happens or when a new related user is started in the
      * background.
      */
-    private void updateRelatedUserIdsLocked() {
-        final List<UserInfo> relatedUsers = getUserManagerLocked().getRelatedUsers(mCurrentUserId);
-        int[] relatedUserIds = new int[relatedUsers.size()]; // relatedUsers will not be null
-        for (int i = 0; i < relatedUserIds.length; i++) {
-            relatedUserIds[i] = relatedUsers.get(i).id;
+    private void updateCurrentProfileIdsLocked() {
+        final List<UserInfo> profiles = getUserManagerLocked().getProfiles(mCurrentUserId);
+        int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
+        for (int i = 0; i < currentProfileIds.length; i++) {
+            currentProfileIds[i] = profiles.get(i).id;
         }
-        mRelatedUserIds = relatedUserIds;
+        mCurrentProfileIds = currentProfileIds;
     }
 
-    private Set getRelatedUsersLocked(int userId) {
+    private Set getProfileIdsLocked(int userId) {
         Set userIds = new HashSet<Integer>();
-        final List<UserInfo> relatedUsers = getUserManagerLocked().getRelatedUsers(userId);
-        for (UserInfo user : relatedUsers) {
+        final List<UserInfo> profiles = getUserManagerLocked().getProfiles(userId);
+        for (UserInfo user : profiles) {
             userIds.add(Integer.valueOf(user.id));
         }
         return userIds;
@@ -16384,15 +16390,15 @@
 
                 if (foreground) {
                     mCurrentUserId = userId;
-                    updateRelatedUserIdsLocked();
-                    mWindowManager.setCurrentUser(userId, mRelatedUserIds);
+                    updateCurrentProfileIdsLocked();
+                    mWindowManager.setCurrentUser(userId, mCurrentProfileIds);
                     // Once the internal notion of the active user has switched, we lock the device
                     // with the option to show the user switcher on the keyguard.
                     mWindowManager.lockNow(null);
                 } else {
                     final Integer currentUserIdInt = Integer.valueOf(mCurrentUserId);
-                    updateRelatedUserIdsLocked();
-                    mWindowManager.updateRelatedUserIds(mRelatedUserIds);
+                    updateCurrentProfileIdsLocked();
+                    mWindowManager.setCurrentProfileIds(mCurrentProfileIds);
                     mUserLru.remove(currentUserIdInt);
                     mUserLru.add(currentUserIdInt);
                 }
@@ -16612,20 +16618,21 @@
         }
     }
 
-    void scheduleStartRelatedUsersLocked() {
-        if (!mHandler.hasMessages(START_RELATED_USERS_MSG)) {
-            mHandler.sendMessageDelayed(mHandler.obtainMessage(START_RELATED_USERS_MSG),
+    void scheduleStartProfilesLocked() {
+        if (!mHandler.hasMessages(START_PROFILES_MSG)) {
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(START_PROFILES_MSG),
                     DateUtils.SECOND_IN_MILLIS);
         }
     }
 
-    void startRelatedUsersLocked() {
-        if (DEBUG_MU) Slog.i(TAG_MU, "startRelatedUsersLocked");
-        List<UserInfo> relatedUsers = getUserManagerLocked().getRelatedUsers(mCurrentUserId);
-        List<UserInfo> toStart = new ArrayList<UserInfo>(relatedUsers.size());
-        for (UserInfo relatedUser : relatedUsers) {
-            if ((relatedUser.flags & UserInfo.FLAG_INITIALIZED) == UserInfo.FLAG_INITIALIZED) {
-                toStart.add(relatedUser);
+    void startProfilesLocked() {
+        if (DEBUG_MU) Slog.i(TAG_MU, "startProfilesLocked");
+        List<UserInfo> profiles = getUserManagerLocked().getProfiles(mCurrentUserId);
+        List<UserInfo> toStart = new ArrayList<UserInfo>(profiles.size());
+        for (UserInfo user : profiles) {
+            if ((user.flags & UserInfo.FLAG_INITIALIZED) == UserInfo.FLAG_INITIALIZED
+                    && user.id != mCurrentUserId) {
+                toStart.add(user);
             }
         }
         final int n = toStart.size();
@@ -16634,7 +16641,7 @@
             startUserInBackground(toStart.get(i).id);
         }
         if (i < n) {
-            Slog.w(TAG_MU, "More related users than MAX_RUNNING_USERS");
+            Slog.w(TAG_MU, "More profiles than MAX_RUNNING_USERS");
         }
     }
 
@@ -16653,7 +16660,7 @@
                         true, false, MY_PID, Process.SYSTEM_UID, userId);
             }
 
-            startRelatedUsersLocked();
+            startProfilesLocked();
 
             int num = mUserLru.size();
             int i = 0;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 3db3a26..d949ba0 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -341,18 +341,17 @@
     }
 
     /**
-     * Checks whether the userid is either the current user or a related user.
+     * Checks whether the userid is a profile of the current user.
      */
-    private boolean isRelatedToOrCurrentUserLocked(int userId) {
-        if (mCurrentUser == userId) return true;
-        for (int i = 0; i < mService.mRelatedUserIds.length; i++) {
-            if (mService.mRelatedUserIds[i] == userId) return true;
+    private boolean isCurrentProfileLocked(int userId) {
+        for (int i = 0; i < mService.mCurrentProfileIds.length; i++) {
+            if (mService.mCurrentProfileIds[i] == userId) return true;
         }
         return false;
     }
 
     boolean okToShowLocked(ActivityRecord r) {
-        return isRelatedToOrCurrentUserLocked(r.userId)
+        return isCurrentProfileLocked(r.userId)
                 || (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0;
     }
 
@@ -571,7 +570,7 @@
 
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             TaskRecord task = mTaskHistory.get(taskNdx);
-            if (!isRelatedToOrCurrentUserLocked(task.userId)) {
+            if (!isCurrentProfileLocked(task.userId)) {
                 return null;
             }
             final ArrayList<ActivityRecord> activities = task.mActivities;
@@ -602,7 +601,7 @@
         int index = mTaskHistory.size();
         for (int i = 0; i < index; ) {
             TaskRecord task = mTaskHistory.get(i);
-            if (isRelatedToOrCurrentUserLocked(task.userId)) {
+            if (isCurrentProfileLocked(task.userId)) {
                 if (DEBUG_TASKS) Slog.d(TAG, "switchUserLocked: stack=" + getStackId() +
                         " moving " + task + " to top");
                 mTaskHistory.remove(i);
@@ -1189,6 +1188,7 @@
                         // At this point, nothing else needs to be shown
                         if (DEBUG_VISBILITY) Slog.v(TAG, "Fullscreen: at " + r);
                         behindFullscreen = true;
+                        showHomeBehindStack = false;
                     } else if (isActivityOverHome(r)) {
                         if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
                         showHomeBehindStack = true;
@@ -1765,10 +1765,10 @@
         mTaskHistory.remove(task);
         // Now put task at top.
         int stackNdx = mTaskHistory.size();
-        if (!isRelatedToOrCurrentUserLocked(task.userId)) {
+        if (!isCurrentProfileLocked(task.userId)) {
             // Put non-current user tasks below current user tasks.
             while (--stackNdx >= 0) {
-                if (!isRelatedToOrCurrentUserLocked(mTaskHistory.get(stackNdx).userId)) {
+                if (!isCurrentProfileLocked(mTaskHistory.get(stackNdx).userId)) {
                     break;
                 }
             }
@@ -2707,6 +2707,9 @@
         if (mResumedActivity == r) {
             mResumedActivity = null;
         }
+        if (mPausingActivity == r) {
+            mPausingActivity = null;
+        }
         if (mService.mFocusedActivity == r) {
             mService.mFocusedActivity = null;
         }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecService.java b/services/core/java/com/android/server/hdmi/HdmiCecService.java
index 36a6e84..0a7236c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecService.java
@@ -37,6 +37,8 @@
 import java.util.ArrayList;
 import java.util.Locale;
 
+import libcore.util.EmptyArray;
+
 /**
  * Provides a service for sending and processing HDMI-CEC messages, and providing
  * the information on HDMI settings in general.
@@ -63,6 +65,8 @@
 
     private static final String PERMISSION = "android.permission.HDMI_CEC";
 
+    private static final byte[] EMPTY_PARAM = EmptyArray.BYTE;
+
     public HdmiCecService(Context context) {
         super(context);
     }
@@ -285,7 +289,13 @@
             synchronized (mLock) {
                 HdmiCecDevice device = getLogicalDeviceLocked(b);
                 device.setIsActiveSource(true);
-                nativeSendActiveSource(mNativePtr, device.getType());
+                int physicalAddress = nativeGetPhysicalAddress(mNativePtr);
+                byte[] param = new byte[] {
+                    (byte) ((physicalAddress >> 8) & 0xff),
+                    (byte) (physicalAddress & 0xff)
+                };
+                nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_BROADCAST,
+                        HdmiCec.MESSAGE_ACTIVE_SOURCE, param);
             }
         }
 
@@ -295,7 +305,8 @@
             synchronized (mLock) {
                 HdmiCecDevice device = getLogicalDeviceLocked(b);
                 device.setIsActiveSource(false);
-                nativeSendInactiveSource(mNativePtr, device.getType());
+                nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_BROADCAST,
+                        HdmiCec.MESSAGE_INACTIVE_SOURCE, EMPTY_PARAM);
             }
         }
 
@@ -304,7 +315,8 @@
             enforceAccessPermission();
             synchronized (mLock) {
                 HdmiCecDevice device = getLogicalDeviceLocked(b);
-                nativeSendImageViewOn(mNativePtr, device.getType());
+                nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_TV,
+                        HdmiCec.MESSAGE_IMAGE_VIEW_ON, EMPTY_PARAM);
             }
         }
 
@@ -313,7 +325,8 @@
             enforceAccessPermission();
             synchronized (mLock) {
                 HdmiCecDevice device = getLogicalDeviceLocked(b);
-                nativeSendTextViewOn(mNativePtr, device.getType());
+                nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_TV,
+                        HdmiCec.MESSAGE_TEXT_VIEW_ON, EMPTY_PARAM);
             }
         }
 
@@ -322,7 +335,8 @@
             enforceAccessPermission();
             synchronized (mLock) {
                 HdmiCecDevice device = getLogicalDeviceLocked(b);
-                nativeSendGiveDevicePowerStatus(mNativePtr, device.getType(), address);
+                nativeSendMessage(mNativePtr, device.getType(), address,
+                        HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS, EMPTY_PARAM);
             }
         }
 
@@ -366,7 +380,8 @@
             if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                     != PackageManager.PERMISSION_GRANTED) {
                 pw.println("Permission denial: can't dump HdmiCecService from pid="
-                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
+                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+                        + " without permission " + android.Manifest.permission.DUMP);
                 return;
             }
             final long ident = Binder.clearCallingIdentity();
@@ -382,10 +397,5 @@
     private static native void nativeRemoveLogicalAddress(long handler, int deviceType);
     private static native void nativeSendMessage(long handler, int deviceType, int destination,
             int opcode, byte[] params);
-    private static native void nativeSendActiveSource(long handler, int deviceType);
-    private static native void nativeSendInactiveSource(long handler, int deviceType);
-    private static native void nativeSendImageViewOn(long handler, int deviceType);
-    private static native void nativeSendTextViewOn(long handler, int deviceType);
-    private static native void nativeSendGiveDevicePowerStatus(long handler, int deviceType,
-            int address);
+    private static native int nativeGetPhysicalAddress(long handler);
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3bc7f4f..3b6d288 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -65,8 +65,8 @@
 import android.service.notification.StatusBarNotification;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.AtomicFile;
-import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -76,9 +76,9 @@
 import android.widget.Toast;
 
 import com.android.internal.R;
-
 import com.android.internal.notification.NotificationScorer;
 import com.android.server.EventLogTags;
+import com.android.server.notification.NotificationUsageStats.SingleNotificationStats;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.SystemService;
 import com.android.server.lights.Light;
@@ -169,7 +169,8 @@
     // used as a mutex for access to all active notifications & listeners
     final ArrayList<NotificationRecord> mNotificationList =
             new ArrayList<NotificationRecord>();
-
+    final ArrayMap<String, NotificationRecord> mNotificationsByKey =
+            new ArrayMap<String, NotificationRecord>();
     final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
 
     ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();
@@ -205,6 +206,8 @@
 
     final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>();
 
+    private final NotificationUsageStats mUsageStats = new NotificationUsageStats();
+
     private int mZenMode;
     // temporary, until we update apps to provide metadata
     private static final Set<String> CALL_PACKAGES = new HashSet<String>(Arrays.asList(
@@ -216,8 +219,8 @@
             ));
     private static final String EXTRA_INTERCEPT = "android.intercept";
 
-    // Users related to the current user.
-    final protected SparseArray<UserInfo> mRelatedUsers = new SparseArray<UserInfo>();
+    // Profiles of the current user.
+    final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
 
     private static final int MY_UID = Process.myUid();
     private static final int MY_PID = Process.myPid();
@@ -661,6 +664,7 @@
 
                             @Override
                             public void onServiceConnected(ComponentName name, IBinder service) {
+                                boolean added = false;
                                 synchronized (mNotificationList) {
                                     mServicesBinding.remove(servicesBindingTag);
                                     try {
@@ -669,11 +673,20 @@
                                                 = new NotificationListenerInfo(
                                                 mListener, name, userid, this);
                                         service.linkToDeath(info, 0);
-                                        mListeners.add(info);
+                                        added = mListeners.add(info);
                                     } catch (RemoteException e) {
                                         // already dead
                                     }
                                 }
+                                if (added) {
+                                    final String[] keys =
+                                            getActiveNotificationKeysFromListener(mListener);
+                                    try {
+                                        mListener.onListenerConnected(keys);
+                                    } catch (RemoteException e) {
+                                        // we tried
+                                    }
+                                }
                             }
 
                             @Override
@@ -763,7 +776,7 @@
         }
     }
 
-    private NotificationListenerInfo checkListenerToken(INotificationListener listener) {
+    private NotificationListenerInfo checkListenerTokenLocked(INotificationListener listener) {
         checkNullListener(listener);
         final IBinder token = listener.asBinder();
         final int N = mListeners.size();
@@ -781,6 +794,7 @@
     public static final class NotificationRecord
     {
         final StatusBarNotification sbn;
+        final SingleNotificationStats stats = new SingleNotificationStats();
         IBinder statusBarKey;
 
         NotificationRecord(StatusBarNotification sbn)
@@ -799,6 +813,7 @@
             pw.println(prefix + "  icon=0x" + Integer.toHexString(notification.icon)
                     + " / " + idDebugString(baseContext, sbn.getPackageName(), notification.icon));
             pw.println(prefix + "  pri=" + notification.priority + " score=" + sbn.getScore());
+            pw.println(prefix + "  key=" + sbn.getKey());
             pw.println(prefix + "  contentIntent=" + notification.contentIntent);
             pw.println(prefix + "  deleteIntent=" + notification.deleteIntent);
             pw.println(prefix + "  tickerText=" + notification.tickerText);
@@ -850,15 +865,17 @@
                 }
                 pw.println(prefix + "  }");
             }
+            pw.println(prefix + "  stats=" + stats.toString());
         }
 
         @Override
         public final String toString() {
             return String.format(
-                    "NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s score=%d: %s)",
+                    "NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s score=%d key=%s: %s)",
                     System.identityHashCode(this),
                     this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(),
-                    this.sbn.getTag(), this.sbn.getScore(), this.sbn.getNotification());
+                    this.sbn.getTag(), this.sbn.getScore(), this.sbn.getKey(),
+                    this.sbn.getNotification());
         }
     }
 
@@ -927,7 +944,9 @@
 
         @Override
         public void onClearAll(int callingUid, int callingPid, int userId) {
-            cancelAll(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null);
+            synchronized (mNotificationList) {
+                cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null);
+            }
         }
 
         @Override
@@ -1101,9 +1120,9 @@
             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
                 // reload per-user settings
                 mSettingsObserver.update(null);
-                updateRelatedUserCache(context);
+                updateCurrentProfilesCache(context);
             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
-                updateRelatedUserCache(context);
+                updateCurrentProfilesCache(context);
             }
         }
     };
@@ -1552,19 +1571,40 @@
          * @param token The binder for the listener, to check that the caller is allowed
          */
         @Override
-        public void cancelAllNotificationsFromListener(INotificationListener token) {
-            NotificationListenerInfo info = checkListenerToken(token);
+        public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
             final int callingUid = Binder.getCallingUid();
             final int callingPid = Binder.getCallingPid();
             long identity = Binder.clearCallingIdentity();
             try {
-                cancelAll(callingUid, callingPid, info.userid,
-                        REASON_LISTENER_CANCEL_ALL, info);
+                synchronized (mNotificationList) {
+                    final NotificationListenerInfo info = checkListenerTokenLocked(token);
+                    if (keys != null) {
+                        final int N = keys.length;
+                        for (int i = 0; i < N; i++) {
+                            NotificationRecord r = mNotificationsByKey.get(keys[i]);
+                            if (r != null) {
+                                cancelNotificationFromListenerLocked(info, callingUid, callingPid,
+                                        r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId());
+                            }
+                        }
+                    } else {
+                        cancelAllLocked(callingUid, callingPid, info.userid,
+                                REASON_LISTENER_CANCEL_ALL, info);
+                    }
+                }
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
         }
 
+        private void cancelNotificationFromListenerLocked(NotificationListenerInfo info,
+                int callingUid, int callingPid, String pkg, String tag, int id) {
+            cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
+                    Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
+                    true,
+                    info.userid, REASON_LISTENER_CANCEL, info);
+        }
+
         /**
          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
          *
@@ -1575,15 +1615,15 @@
         @Override
         public void cancelNotificationFromListener(INotificationListener token, String pkg,
                 String tag, int id) {
-            NotificationListenerInfo info = checkListenerToken(token);
             final int callingUid = Binder.getCallingUid();
             final int callingPid = Binder.getCallingPid();
             long identity = Binder.clearCallingIdentity();
             try {
-                cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
-                        Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
-                        true,
-                        info.userid, REASON_LISTENER_CANCEL, info);
+                synchronized (mNotificationList) {
+                    final NotificationListenerInfo info = checkListenerTokenLocked(token);
+                    cancelNotificationFromListenerLocked(info, callingUid, callingPid,
+                            pkg, tag, id);
+                }
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -1598,21 +1638,35 @@
          */
         @Override
         public StatusBarNotification[] getActiveNotificationsFromListener(
-                INotificationListener token) {
-            NotificationListenerInfo info = checkListenerToken(token);
-
-            StatusBarNotification[] result = new StatusBarNotification[0];
-            ArrayList<StatusBarNotification> list = new ArrayList<StatusBarNotification>();
+                INotificationListener token, String[] keys) {
             synchronized (mNotificationList) {
-                final int N = mNotificationList.size();
-                for (int i=0; i<N; i++) {
-                    StatusBarNotification sbn = mNotificationList.get(i).sbn;
-                    if (info.enabledAndUserMatches(sbn)) {
-                        list.add(sbn);
+                final NotificationListenerInfo info = checkListenerTokenLocked(token);
+                final ArrayList<StatusBarNotification> list
+                        = new ArrayList<StatusBarNotification>();
+                if (keys == null) {
+                    final int N = mNotificationList.size();
+                    for (int i=0; i<N; i++) {
+                        StatusBarNotification sbn = mNotificationList.get(i).sbn;
+                        if (info.enabledAndUserMatches(sbn)) {
+                            list.add(sbn);
+                        }
+                    }
+                } else {
+                    final int N = keys.length;
+                    for (int i=0; i<N; i++) {
+                        NotificationRecord r = mNotificationsByKey.get(keys[i]);
+                        if (r != null && info.enabledAndUserMatches(r.sbn)) {
+                            list.add(r.sbn);
+                        }
                     }
                 }
+                return list.toArray(new StatusBarNotification[list.size()]);
             }
-            return list.toArray(result);
+        }
+
+        @Override
+        public String[] getActiveNotificationKeysFromListener(INotificationListener token) {
+            return NotificationManagerService.this.getActiveNotificationKeysFromListener(token);
         }
 
         @Override
@@ -1629,6 +1683,21 @@
         }
     };
 
+    private String[] getActiveNotificationKeysFromListener(INotificationListener token) {
+        synchronized (mNotificationList) {
+            final NotificationListenerInfo info = checkListenerTokenLocked(token);
+            final ArrayList<String> keys = new ArrayList<String>();
+            final int N = mNotificationList.size();
+            for (int i=0; i<N; i++) {
+                final StatusBarNotification sbn = mNotificationList.get(i).sbn;
+                if (info.enabledAndUserMatches(sbn)) {
+                    keys.add(sbn.getKey());
+                }
+            }
+            return keys.toArray(new String[keys.size()]);
+        }
+    }
+
     void dumpImpl(PrintWriter pw) {
         pw.println("Current Notification Manager state:");
 
@@ -1694,6 +1763,9 @@
                 }
             }
 
+            pw.println("\n  Usage Stats:");
+            mUsageStats.dump(pw, "    ");
+
         }
     }
 
@@ -1841,15 +1913,21 @@
                     int index = indexOfNotificationLocked(pkg, tag, id, userId);
                     if (index < 0) {
                         mNotificationList.add(r);
+                        mUsageStats.registerPostedByApp(r);
                     } else {
                         old = mNotificationList.remove(index);
                         mNotificationList.add(index, r);
+                        mUsageStats.registerUpdatedByApp(r);
                         // Make sure we don't lose the foreground service state.
                         if (old != null) {
                             notification.flags |=
                                 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
                         }
                     }
+                    if (old != null) {
+                        mNotificationsByKey.remove(old.sbn.getKey());
+                    }
+                    mNotificationsByKey.put(n.getKey(), r);
 
                     // Ensure if this is a foreground service that the proper additional
                     // flags are set.
@@ -2232,7 +2310,7 @@
         manager.sendAccessibilityEvent(event);
     }
 
-    private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete) {
+    private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
         // tell the app
         if (sendDelete) {
             if (r.getNotification().deleteIntent != null) {
@@ -2291,6 +2369,26 @@
             mLedNotification = null;
         }
 
+        // Record usage stats
+        switch (reason) {
+            case REASON_DELEGATE_CANCEL:
+            case REASON_DELEGATE_CANCEL_ALL:
+            case REASON_LISTENER_CANCEL:
+            case REASON_LISTENER_CANCEL_ALL:
+                mUsageStats.registerDismissedByUser(r);
+                break;
+            case REASON_NOMAN_CANCEL:
+            case REASON_NOMAN_CANCEL_ALL:
+                mUsageStats.registerRemovedByApp(r);
+                break;
+            case REASON_DELEGATE_CLICK:
+                mUsageStats.registerCancelDueToClick(r);
+                break;
+            default:
+                mUsageStats.registerCancelUnknown(r);
+                break;
+        }
+
         // Save it for users of getHistoricalNotifications()
         mArchive.record(r.sbn);
     }
@@ -2319,6 +2417,12 @@
                     if (index >= 0) {
                         NotificationRecord r = mNotificationList.get(index);
 
+                        // Ideally we'd do this in the caller of this method. However, that would
+                        // require the caller to also find the notification.
+                        if (reason == REASON_DELEGATE_CLICK) {
+                            mUsageStats.registerClickedByUser(r);
+                        }
+
                         if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
                             return;
                         }
@@ -2327,8 +2431,9 @@
                         }
 
                         mNotificationList.remove(index);
+                        mNotificationsByKey.remove(r.sbn.getKey());
 
-                        cancelNotificationLocked(r, sendDelete);
+                        cancelNotificationLocked(r, sendDelete, reason);
                         updateLightsLocked();
                     }
                 }
@@ -2353,12 +2458,12 @@
     /**
      * Determine whether the userId applies to the notification in question, either because
      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
-     * because it matches a related user.
+     * because it matches one of the users profiles.
      */
-    private boolean notificationMatchesUserIdOrRelated(NotificationRecord r, int userId) {
-        synchronized (mRelatedUsers) {
+    private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
+        synchronized (mCurrentProfiles) {
             return notificationMatchesUserId(r, userId)
-                    || mRelatedUsers.get(r.getUserId()) != null;
+                    || mCurrentProfiles.get(r.getUserId()) != null;
         }
     }
 
@@ -2399,7 +2504,8 @@
                     return true;
                 }
                 mNotificationList.remove(i);
-                cancelNotificationLocked(r, false);
+                mNotificationsByKey.remove(r.sbn.getKey());
+                cancelNotificationLocked(r, false, reason);
             }
             if (canceledSomething) {
                 updateLightsLocked();
@@ -2446,29 +2552,27 @@
         }
     }
 
-    void cancelAll(int callingUid, int callingPid, int userId, int reason,
+    void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
             NotificationListenerInfo listener) {
         EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
                 null, userId, 0, 0, reason,
                 listener == null ? null : listener.component.toShortString());
-        synchronized (mNotificationList) {
-            final int N = mNotificationList.size();
-            for (int i=N-1; i>=0; i--) {
-                NotificationRecord r = mNotificationList.get(i);
 
-                if (!notificationMatchesUserIdOrRelated(r, userId)) {
-                    continue;
-                }
-
-                if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
-                                | Notification.FLAG_NO_CLEAR)) == 0) {
-                    mNotificationList.remove(i);
-                    cancelNotificationLocked(r, true);
-                }
+        final int N = mNotificationList.size();
+        for (int i=N-1; i>=0; i--) {
+            NotificationRecord r = mNotificationList.get(i);
+            if (!notificationMatchesCurrentProfiles(r, userId)) {
+                continue;
             }
 
-            updateLightsLocked();
+            if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
+                            | Notification.FLAG_NO_CLEAR)) == 0) {
+                mNotificationList.remove(i);
+                mNotificationsByKey.remove(r.sbn.getKey());
+                cancelNotificationLocked(r, true, reason);
+            }
         }
+        updateLightsLocked();
     }
 
     // lock on mNotificationList
@@ -2572,15 +2676,15 @@
                 exceptionPackages);
     }
 
-    private void updateRelatedUserCache(Context context) {
+    private void updateCurrentProfilesCache(Context context) {
         UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
         int currentUserId = ActivityManager.getCurrentUser();
         if (userManager != null) {
-            List<UserInfo> relatedUsers = userManager.getRelatedUsers(currentUserId);
-            synchronized (mRelatedUsers) {
-                mRelatedUsers.clear();
-                for (UserInfo related : relatedUsers) {
-                    mRelatedUsers.put(related.id, related);
+            List<UserInfo> profiles = userManager.getProfiles(currentUserId);
+            synchronized (mCurrentProfiles) {
+                mCurrentProfiles.clear();
+                for (UserInfo user : profiles) {
+                    mCurrentProfiles.put(user.id, user);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
new file mode 100644
index 0000000..faa5a43
--- /dev/null
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -0,0 +1,271 @@
+/*
+ * 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.notification;
+
+import com.android.server.notification.NotificationManagerService.NotificationRecord;
+
+import android.os.SystemClock;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Keeps track of notification activity, display, and user interaction.
+ *
+ * <p>This class receives signals from NoMan and keeps running stats of
+ * notification usage. Some metrics are updated as events occur. Others, namely
+ * those involving durations, are updated as the notification is canceled.</p>
+ *
+ * <p>This class is thread-safe.</p>
+ *
+ * {@hide}
+ */
+public class NotificationUsageStats {
+
+    // Guarded by synchronized(this).
+    private final Map<String, AggregatedStats> mStats = new HashMap<String, AggregatedStats>();
+
+    /**
+     * Called when a notification has been posted.
+     */
+    public synchronized void registerPostedByApp(NotificationRecord notification) {
+        notification.stats.posttimeElapsedMs = SystemClock.elapsedRealtime();
+        for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
+            stats.numPostedByApp++;
+        }
+    }
+
+    /**
+     * Called when a notification has been updated.
+     */
+    public void registerUpdatedByApp(NotificationRecord notification) {
+        for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
+            stats.numUpdatedByApp++;
+        }
+    }
+
+    /**
+     * Called when the originating app removed the notification programmatically.
+     */
+    public synchronized void registerRemovedByApp(NotificationRecord notification) {
+        for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
+            stats.numRemovedByApp++;
+            stats.collect(notification.stats);
+        }
+    }
+
+    /**
+     * Called when the user dismissed the notification via the UI.
+     */
+    public synchronized void registerDismissedByUser(NotificationRecord notification) {
+        notification.stats.onDismiss();
+        for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
+            stats.numDismissedByUser++;
+            stats.collect(notification.stats);
+        }
+    }
+
+    /**
+     * Called when the user clicked the notification in the UI.
+     */
+    public synchronized void registerClickedByUser(NotificationRecord notification) {
+        notification.stats.onClick();
+        for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
+            stats.numClickedByUser++;
+        }
+    }
+
+    /**
+     * Called when the notification is canceled because the user clicked it.
+     *
+     * <p>Called after {@link #registerClickedByUser(NotificationRecord)}.</p>
+     */
+    public synchronized void registerCancelDueToClick(NotificationRecord notification) {
+        // No explicit stats for this (the click has already been registered in
+        // registerClickedByUser), just make sure the single notification stats
+        // are folded up into aggregated stats.
+        for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
+            stats.collect(notification.stats);
+        }
+    }
+
+    /**
+     * Called when the notification is canceled due to unknown reasons.
+     *
+     * <p>Called for notifications of apps being uninstalled, for example.</p>
+     */
+    public synchronized void registerCancelUnknown(NotificationRecord notification) {
+        // Fold up individual stats.
+        for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
+            stats.collect(notification.stats);
+        }
+    }
+
+    // Locked by this.
+    private AggregatedStats[] getAggregatedStatsLocked(NotificationRecord record) {
+        StatusBarNotification n = record.sbn;
+
+        String user = String.valueOf(n.getUserId());
+        String userPackage = user + ":" + n.getPackageName();
+
+        // TODO: Use pool of arrays.
+        return new AggregatedStats[] {
+                getOrCreateAggregatedStatsLocked(user),
+                getOrCreateAggregatedStatsLocked(userPackage),
+                getOrCreateAggregatedStatsLocked(n.getKey()),
+        };
+    }
+
+    // Locked by this.
+    private AggregatedStats getOrCreateAggregatedStatsLocked(String key) {
+        AggregatedStats result = mStats.get(key);
+        if (result == null) {
+            result = new AggregatedStats(key);
+            mStats.put(key, result);
+        }
+        return result;
+    }
+
+    public synchronized void dump(PrintWriter pw, String indent) {
+        for (AggregatedStats as : mStats.values()) {
+            as.dump(pw, indent);
+        }
+    }
+
+    /**
+     * Aggregated notification stats.
+     */
+    private static class AggregatedStats {
+        public final String key;
+
+        // ---- Updated as the respective events occur.
+        public int numPostedByApp;
+        public int numUpdatedByApp;
+        public int numRemovedByApp;
+        public int numClickedByUser;
+        public int numDismissedByUser;
+
+        // ----  Updated when a notification is canceled.
+        public final Aggregate posttimeMs = new Aggregate();
+        public final Aggregate posttimeToDismissMs = new Aggregate();
+        public final Aggregate posttimeToFirstClickMs = new Aggregate();
+
+        public AggregatedStats(String key) {
+            this.key = key;
+        }
+
+        public void collect(SingleNotificationStats singleNotificationStats) {
+            posttimeMs.addSample(
+	            SystemClock.elapsedRealtime() - singleNotificationStats.posttimeElapsedMs);
+            if (singleNotificationStats.posttimeToDismissMs >= 0) {
+                posttimeToDismissMs.addSample(singleNotificationStats.posttimeToDismissMs);
+            }
+            if (singleNotificationStats.posttimeToFirstClickMs >= 0) {
+                posttimeToFirstClickMs.addSample(singleNotificationStats.posttimeToFirstClickMs);
+            }
+        }
+
+        public void dump(PrintWriter pw, String indent) {
+            pw.println(toStringWithIndent(indent));
+        }
+
+        @Override
+        public String toString() {
+            return toStringWithIndent("");
+        }
+
+        private String toStringWithIndent(String indent) {
+            return indent + "AggregatedStats{\n" +
+                    indent + "  key='" + key + "',\n" +
+                    indent + "  numPostedByApp=" + numPostedByApp + ",\n" +
+                    indent + "  numUpdatedByApp=" + numUpdatedByApp + ",\n" +
+                    indent + "  numRemovedByApp=" + numRemovedByApp + ",\n" +
+                    indent + "  numClickedByUser=" + numClickedByUser + ",\n" +
+                    indent + "  numDismissedByUser=" + numDismissedByUser + ",\n" +
+                    indent + "  posttimeMs=" + posttimeMs + ",\n" +
+                    indent + "  posttimeToDismissMs=" + posttimeToDismissMs + ",\n" +
+                    indent + "  posttimeToFirstClickMs=" + posttimeToFirstClickMs + ",\n" +
+                    indent + "}";
+        }
+    }
+
+    /**
+     * Tracks usage of an individual notification that is currently active.
+     */
+    public static class SingleNotificationStats {
+        /** SystemClock.elapsedRealtime() when the notification was posted. */
+        public long posttimeElapsedMs = -1;
+        /** Elapsed time since the notification was posted until it was first clicked, or -1. */
+        public long posttimeToFirstClickMs = -1;
+        /** Elpased time since the notification was posted until it was dismissed by the user. */
+        public long posttimeToDismissMs = -1;
+
+        /**
+         * Called when the user clicked the notification.
+         */
+        public void onClick() {
+            if (posttimeToFirstClickMs < 0) {
+                posttimeToFirstClickMs = SystemClock.elapsedRealtime() - posttimeElapsedMs;
+            }
+        }
+
+        /**
+         * Called when the user removed the notification.
+         */
+        public void onDismiss() {
+            if (posttimeToDismissMs < 0) {
+                posttimeToDismissMs = SystemClock.elapsedRealtime() - posttimeElapsedMs;
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "SingleNotificationStats{" +
+                    "posttimeElapsedMs=" + posttimeElapsedMs +
+                    ", posttimeToFirstClickMs=" + posttimeToFirstClickMs +
+                    ", posttimeToDismissMs=" + posttimeToDismissMs +
+                    '}';
+        }
+    }
+
+    /**
+     * Aggregates long samples to sum and averages.
+     */
+    public static class Aggregate {
+        long numSamples;
+        long sum;
+        long avg;
+
+        public void addSample(long sample) {
+            numSamples++;
+            sum += sample;
+            avg = sum / numSamples;
+        }
+
+        @Override
+        public String toString() {
+            return "Aggregate{" +
+                    "numSamples=" + numSamples +
+                    ", sum=" + sum +
+                    ", avg=" + avg +
+                    '}';
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index ae1cfab..ff816ea 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -407,7 +407,14 @@
         return execute(builder.toString());
     }
 
-    public boolean restoreconData() {
-        return (execute("restorecondata") == 0);
+    public boolean restoreconData(String pkgName, String seinfo, int uid) {
+        StringBuilder builder = new StringBuilder("restorecondata");
+        builder.append(' ');
+        builder.append(pkgName);
+        builder.append(' ');
+        builder.append(seinfo != null ? seinfo : "!");
+        builder.append(' ');
+        builder.append(uid);
+        return (execute(builder.toString()) == 0);
     }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a01c586..288e8e0 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -69,6 +69,7 @@
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.IPackageInstallObserver;
+import android.content.pm.IPackageInstallObserver2;
 import android.content.pm.IPackageManager;
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
@@ -340,7 +341,7 @@
 
     // Lock for state used when installing and doing other long running
     // operations.  Methods that must be called with this lock held have
-    // the prefix "LI".
+    // the suffix "LI".
     final Object mInstallLock = new Object();
 
     // These are the directories in the 3rd party applications installed dir
@@ -401,6 +402,9 @@
     // If mac_permissions.xml was found for seinfo labeling.
     boolean mFoundPolicyFile;
 
+    // If a recursive restorecon of /data/data/<pkg> is needed.
+    private boolean mShouldRestoreconData = SELinuxMMAC.shouldRestorecon();
+
     // All available activities, for your resolving pleasure.
     final ActivityIntentResolver mActivities =
             new ActivityIntentResolver();
@@ -696,7 +700,7 @@
                                     // Just post MCS_BOUND message to trigger processing
                                     // of next pending install.
                                     if (DEBUG_SD_INSTALL) Log.i(TAG,
-                                            "Posting MCS_BOUND for next woek");
+                                            "Posting MCS_BOUND for next work");
                                     mHandler.sendEmptyMessage(MCS_BOUND);
                                 }
                             }
@@ -916,6 +920,14 @@
                                 Slog.i(TAG, "Observer no longer exists.");
                             }
                         }
+                        if (args.observer2 != null) {
+                            try {
+                                Bundle extras = extrasForInstallResult(res);
+                                args.observer2.packageInstalled(res.name, extras, res.returnCode);
+                            } catch (RemoteException e) {
+                                Slog.i(TAG, "Observer no longer exists.");
+                            }
+                        }
                     } else {
                         Slog.e(TAG, "Bogus post-install token " + msg.arg1);
                     }
@@ -1044,6 +1056,21 @@
         }
     }
 
+    Bundle extrasForInstallResult(PackageInstalledInfo res) {
+        Bundle extras = null;
+        switch (res.returnCode) {
+            case PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION: {
+                extras = new Bundle();
+                extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PERMISSION,
+                        res.origPermission);
+                extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE,
+                        res.origPackage);
+                break;
+            }
+        }
+        return extras;
+    }
+
     void scheduleWriteSettingsLocked() {
         if (!mHandler.hasMessages(WRITE_SETTINGS)) {
             mHandler.sendEmptyMessageDelayed(WRITE_SETTINGS, WRITE_SETTINGS_DELAY);
@@ -1512,13 +1539,6 @@
             // can downgrade to reader
             mSettings.writeLPr();
 
-            if (SELinuxMMAC.shouldRestorecon()) {
-                Slog.i(TAG, "Relabeling of /data/data and /data/user issued.");
-                if (mInstaller.restoreconData()) {
-                    SELinuxMMAC.setRestoreconDone();
-                }
-            }
-
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
                     SystemClock.uptimeMillis());
 
@@ -4763,6 +4783,11 @@
                     }
                 }
                 pkg.applicationInfo.dataDir = dataPath.getPath();
+                if (mShouldRestoreconData) {
+                    Slog.i(TAG, "SELinux relabeling of " + pkg.packageName + " issued.");
+                    mInstaller.restoreconData(pkg.packageName, pkg.applicationInfo.seinfo,
+                                pkg.applicationInfo.uid);
+                }
             } else {
                 if (DEBUG_PACKAGE_SCANNING) {
                     if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
@@ -6772,18 +6797,24 @@
         private final boolean mIsPrivileged;
     }
 
+    /*
+     * The old-style observer methods all just trampoline to the newer signature with
+     * expanded install observer API.  The older API continues to work but does not
+     * supply the additional details of the Observer2 API.
+     */
+
     /* Called when a downloaded package installation has been confirmed by the user */
     public void installPackage(
             final Uri packageURI, final IPackageInstallObserver observer, final int flags) {
-        installPackage(packageURI, observer, flags, null);
+        installPackageEtc(packageURI, observer, null, flags, null);
     }
 
     /* Called when a downloaded package installation has been confirmed by the user */
     public void installPackage(
             final Uri packageURI, final IPackageInstallObserver observer, final int flags,
             final String installerPackageName) {
-        installPackageWithVerification(packageURI, observer, flags, installerPackageName, null,
-                null, null);
+        installPackageWithVerificationEtc(packageURI, observer, null, flags,
+                installerPackageName, null, null, null);
     }
 
     @Override
@@ -6792,20 +6823,67 @@
             ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
         VerificationParams verificationParams = new VerificationParams(verificationURI, null, null,
                 VerificationParams.NO_UID, manifestDigest);
-        installPackageWithVerificationAndEncryption(packageURI, observer, flags,
+        installPackageWithVerificationAndEncryptionEtc(packageURI, observer, null, flags,
                 installerPackageName, verificationParams, encryptionParams);
     }
 
     public void installPackageWithVerificationAndEncryption(Uri packageURI,
             IPackageInstallObserver observer, int flags, String installerPackageName,
             VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
+        installPackageWithVerificationAndEncryptionEtc(packageURI, observer, null, flags,
+                installerPackageName, verificationParams, encryptionParams);
+    }
+
+    /*
+     * And here are the "live" versions that take both observer arguments
+     */
+    public void installPackageEtc(
+            final Uri packageURI, final IPackageInstallObserver observer,
+            IPackageInstallObserver2 observer2, final int flags) {
+        installPackageEtc(packageURI, observer, observer2, flags, null);
+    }
+
+    public void installPackageEtc(
+            final Uri packageURI, final IPackageInstallObserver observer,
+            final IPackageInstallObserver2 observer2, final int flags,
+            final String installerPackageName) {
+        installPackageWithVerificationEtc(packageURI, observer, observer2, flags,
+                installerPackageName, null, null, null);
+    }
+
+    @Override
+    public void installPackageWithVerificationEtc(Uri packageURI, IPackageInstallObserver observer,
+            IPackageInstallObserver2 observer2,
+            int flags, String installerPackageName, Uri verificationURI,
+            ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
+        VerificationParams verificationParams = new VerificationParams(verificationURI, null, null,
+                VerificationParams.NO_UID, manifestDigest);
+        installPackageWithVerificationAndEncryptionEtc(packageURI, observer, observer2, flags,
+                installerPackageName, verificationParams, encryptionParams);
+    }
+
+    /*
+     * All of the installPackage...*() methods redirect to this one for the master implementation
+     */
+    public void installPackageWithVerificationAndEncryptionEtc(Uri packageURI,
+            IPackageInstallObserver observer, IPackageInstallObserver2 observer2,
+            int flags, String installerPackageName,
+            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
+        if (observer == null && observer2 == null) {
+            throw new IllegalArgumentException("No install observer supplied");
+        }
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES,
                 null);
 
         final int uid = Binder.getCallingUid();
         if (isUserRestricted(UserHandle.getUserId(uid), UserManager.DISALLOW_INSTALL_APPS)) {
             try {
-                observer.packageInstalled("", PackageManager.INSTALL_FAILED_USER_RESTRICTED);
+                if (observer != null) {
+                    observer.packageInstalled("", PackageManager.INSTALL_FAILED_USER_RESTRICTED);
+                }
+                if (observer2 != null) {
+                    observer2.packageInstalled("", null, PackageManager.INSTALL_FAILED_USER_RESTRICTED);
+                }
             } catch (RemoteException re) {
             }
             return;
@@ -6832,8 +6910,8 @@
         verificationParams.setInstallerUid(uid);
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
-        msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName,
-                verificationParams, encryptionParams, user);
+        msg.obj = new InstallParams(packageURI, observer, observer2, filteredFlags,
+                installerPackageName, verificationParams, encryptionParams, user);
         mHandler.sendMessage(msg);
     }
 
@@ -7455,32 +7533,34 @@
                 mSuccess = getPackageSizeInfoLI(mStats.packageName, mStats.userHandle, mStats);
             }
 
-            final boolean mounted;
-            if (Environment.isExternalStorageEmulated()) {
-                mounted = true;
-            } else {
-                final String status = Environment.getExternalStorageState();
-                mounted = (Environment.MEDIA_MOUNTED.equals(status)
-                        || Environment.MEDIA_MOUNTED_READ_ONLY.equals(status));
-            }
+            if (mSuccess) {
+                final boolean mounted;
+                if (Environment.isExternalStorageEmulated()) {
+                    mounted = true;
+                } else {
+                    final String status = Environment.getExternalStorageState();
+                    mounted = (Environment.MEDIA_MOUNTED.equals(status)
+                            || Environment.MEDIA_MOUNTED_READ_ONLY.equals(status));
+                }
 
-            if (mounted) {
-                final UserEnvironment userEnv = new UserEnvironment(mStats.userHandle);
+                if (mounted) {
+                    final UserEnvironment userEnv = new UserEnvironment(mStats.userHandle);
 
-                mStats.externalCacheSize = calculateDirectorySize(mContainerService,
-                        userEnv.buildExternalStorageAppCacheDirs(mStats.packageName));
+                    mStats.externalCacheSize = calculateDirectorySize(mContainerService,
+                            userEnv.buildExternalStorageAppCacheDirs(mStats.packageName));
 
-                mStats.externalDataSize = calculateDirectorySize(mContainerService,
-                        userEnv.buildExternalStorageAppDataDirs(mStats.packageName));
+                    mStats.externalDataSize = calculateDirectorySize(mContainerService,
+                            userEnv.buildExternalStorageAppDataDirs(mStats.packageName));
 
-                // Always subtract cache size, since it's a subdirectory
-                mStats.externalDataSize -= mStats.externalCacheSize;
+                    // Always subtract cache size, since it's a subdirectory
+                    mStats.externalDataSize -= mStats.externalCacheSize;
 
-                mStats.externalMediaSize = calculateDirectorySize(mContainerService,
-                        userEnv.buildExternalStorageAppMediaDirs(mStats.packageName));
+                    mStats.externalMediaSize = calculateDirectorySize(mContainerService,
+                            userEnv.buildExternalStorageAppMediaDirs(mStats.packageName));
 
-                mStats.externalObbSize = calculateDirectorySize(mContainerService,
-                        userEnv.buildExternalStorageAppObbDirs(mStats.packageName));
+                    mStats.externalObbSize = calculateDirectorySize(mContainerService,
+                            userEnv.buildExternalStorageAppObbDirs(mStats.packageName));
+                }
             }
         }
 
@@ -7522,6 +7602,7 @@
 
     class InstallParams extends HandlerParams {
         final IPackageInstallObserver observer;
+        final IPackageInstallObserver2 observer2;
         int flags;
 
         private final Uri mPackageURI;
@@ -7533,13 +7614,14 @@
         final ContainerEncryptionParams encryptionParams;
 
         InstallParams(Uri packageURI,
-                IPackageInstallObserver observer, int flags,
-                String installerPackageName, VerificationParams verificationParams,
+                IPackageInstallObserver observer, IPackageInstallObserver2 observer2,
+                int flags, String installerPackageName, VerificationParams verificationParams,
                 ContainerEncryptionParams encryptionParams, UserHandle user) {
             super(user);
             this.mPackageURI = packageURI;
             this.flags = flags;
             this.observer = observer;
+            this.observer2 = observer2;
             this.installerPackageName = installerPackageName;
             this.verificationParams = verificationParams;
             this.encryptionParams = encryptionParams;
@@ -8109,6 +8191,7 @@
 
     static abstract class InstallArgs {
         final IPackageInstallObserver observer;
+        final IPackageInstallObserver2 observer2;
         // Always refers to PackageManager flags only
         final int flags;
         final Uri packageURI;
@@ -8116,12 +8199,14 @@
         final ManifestDigest manifestDigest;
         final UserHandle user;
 
-        InstallArgs(Uri packageURI, IPackageInstallObserver observer, int flags,
-                String installerPackageName, ManifestDigest manifestDigest,
+        InstallArgs(Uri packageURI,
+                IPackageInstallObserver observer, IPackageInstallObserver2 observer2,
+                int flags, String installerPackageName, ManifestDigest manifestDigest,
                 UserHandle user) {
             this.packageURI = packageURI;
             this.flags = flags;
             this.observer = observer;
+            this.observer2 = observer2;
             this.installerPackageName = installerPackageName;
             this.manifestDigest = manifestDigest;
             this.user = user;
@@ -8178,13 +8263,13 @@
         boolean created = false;
 
         FileInstallArgs(InstallParams params) {
-            super(params.getPackageUri(), params.observer, params.flags,
+            super(params.getPackageUri(), params.observer, params.observer2, params.flags,
                     params.installerPackageName, params.getManifestDigest(),
                     params.getUser());
         }
 
         FileInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath) {
-            super(null, null, 0, null, null, null);
+            super(null, null, null, 0, null, null, null);
             File codeFile = new File(fullCodePath);
             installDir = codeFile.getParentFile();
             codeFileName = fullCodePath;
@@ -8193,7 +8278,7 @@
         }
 
         FileInstallArgs(Uri packageURI, String pkgName, String dataDir) {
-            super(packageURI, null, 0, null, null, null);
+            super(packageURI, null, null, 0, null, null, null);
             installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir;
             String apkName = getNextCodePath(null, pkgName, ".apk");
             codeFileName = new File(installDir, apkName + ".apk").getPath();
@@ -8514,14 +8599,14 @@
         String libraryPath;
 
         AsecInstallArgs(InstallParams params) {
-            super(params.getPackageUri(), params.observer, params.flags,
+            super(params.getPackageUri(), params.observer, params.observer2, params.flags,
                     params.installerPackageName, params.getManifestDigest(),
                     params.getUser());
         }
 
         AsecInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath,
                 boolean isExternal, boolean isForwardLocked) {
-            super(null, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0)
+            super(null, null, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0)
                     | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0),
                     null, null, null);
             // Extract cid from fullCodePath
@@ -8533,7 +8618,7 @@
         }
 
         AsecInstallArgs(String cid, boolean isForwardLocked) {
-            super(null, null, (isAsecExternal(cid) ? PackageManager.INSTALL_EXTERNAL : 0)
+            super(null, null, null, (isAsecExternal(cid) ? PackageManager.INSTALL_EXTERNAL : 0)
                     | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0),
                     null, null, null);
             this.cid = cid;
@@ -8541,7 +8626,7 @@
         }
 
         AsecInstallArgs(Uri packageURI, String cid, boolean isExternal, boolean isForwardLocked) {
-            super(packageURI, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0)
+            super(packageURI, null, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0)
                     | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0),
                     null, null, null);
             this.cid = cid;
@@ -8875,6 +8960,10 @@
         PackageParser.Package pkg;
         int returnCode;
         PackageRemovedInfo removedInfo;
+
+        // In some error cases we want to convey more info back to the observer
+        String origPackage;
+        String origPermission;
     }
 
     /*
@@ -9299,6 +9388,27 @@
         String oldCodePath = null;
         boolean systemApp = false;
         synchronized (mPackages) {
+            // Check whether the newly-scanned package wants to define an already-defined perm
+            int N = pkg.permissions.size();
+            for (int i = 0; i < N; i++) {
+                PackageParser.Permission perm = pkg.permissions.get(i);
+                BasePermission bp = mSettings.mPermissions.get(perm.info.name);
+                if (bp != null) {
+                    // If the defining package is signed with our cert, it's okay.  This
+                    // also includes the "updating the same package" case, of course.
+                    if (compareSignatures(bp.packageSetting.signatures.mSignatures,
+                            pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
+                        Slog.w(TAG, "Package " + pkg.packageName
+                                + " attempting to redeclare permission " + perm.info.name
+                                + " already owned by " + bp.sourcePackage);
+                        res.returnCode = PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
+                        res.origPermission = perm.info.name;
+                        res.origPackage = bp.sourcePackage;
+                        return;
+                    }
+                }
+            }
+
             // Check if installing already existing package
             if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
                 String oldName = mSettings.mRenamedPackages.get(pkgName);
@@ -10163,6 +10273,9 @@
             final IPackageStatsObserver observer) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.GET_PACKAGE_SIZE, null);
+        if (packageName == null) {
+            throw new IllegalArgumentException("Attempt to get size of null packageName");
+        }
 
         PackageStats stats = new PackageStats(packageName, userHandle);
 
@@ -11325,6 +11438,10 @@
      */
     public void scanAvailableAsecs() {
         updateExternalMediaStatusInner(true, false, false);
+        if (mShouldRestoreconData) {
+            SELinuxMMAC.setRestoreconDone();
+            mShouldRestoreconData = false;
+        }
     }
 
     /*
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 7f55464..a39e958 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -92,7 +92,7 @@
     private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber";
     private static final String ATTR_PARTIAL = "partial";
     private static final String ATTR_USER_VERSION = "version";
-    private static final String ATTR_RELATED_GROUP_ID = "relatedGroupId";
+    private static final String ATTR_PROFILE_GROUP_ID = "profileGroupId";
     private static final String TAG_USERS = "users";
     private static final String TAG_USER = "user";
     private static final String TAG_RESTRICTIONS = "restrictions";
@@ -257,26 +257,26 @@
     }
 
     @Override
-    public List<UserInfo> getRelatedUsers(int userId) {
+    public List<UserInfo> getProfiles(int userId) {
         checkManageUsersPermission("query users");
         synchronized (mPackagesLock) {
             UserInfo user = getUserInfoLocked(userId);
             ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
             for (int i = 0; i < mUsers.size(); i++) {
-                UserInfo ui = mUsers.valueAt(i);
-                if (!areRelatedUsers(user, ui)) {
+                UserInfo profile = mUsers.valueAt(i);
+                if (!isProfileOf(user, profile)) {
                     continue;
                 }
-                users.add(ui);
+                users.add(profile);
             }
             return users;
         }
     }
 
-    private boolean areRelatedUsers(UserInfo user1, UserInfo user2) {
-        return user1.relatedGroupId != UserInfo.NO_RELATED_GROUP_ID &&
-                user1.relatedGroupId == user2.relatedGroupId &&
-                user1.id != user2.id;
+    private boolean isProfileOf(UserInfo user, UserInfo profile) {
+        return user.id == profile.id ||
+                (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
+                && user.profileGroupId == profile.profileGroupId);
     }
 
     @Override
@@ -684,9 +684,9 @@
             if (userInfo.partial) {
                 serializer.attribute(null, ATTR_PARTIAL, "true");
             }
-            if (userInfo.relatedGroupId != UserInfo.NO_RELATED_GROUP_ID) {
-                serializer.attribute(null, ATTR_RELATED_GROUP_ID,
-                        Integer.toString(userInfo.relatedGroupId));
+            if (userInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID) {
+                serializer.attribute(null, ATTR_PROFILE_GROUP_ID,
+                        Integer.toString(userInfo.profileGroupId));
             }
 
             serializer.startTag(null, TAG_NAME);
@@ -771,7 +771,7 @@
         long salt = 0L;
         String pinHash = null;
         int failedAttempts = 0;
-        int relatedGroupId = UserInfo.NO_RELATED_GROUP_ID;
+        int profileGroupId = UserInfo.NO_PROFILE_GROUP_ID;
         long lastAttemptTime = 0L;
         boolean partial = false;
         Bundle restrictions = new Bundle();
@@ -809,8 +809,14 @@
                 pinHash = parser.getAttributeValue(null, ATTR_PIN_HASH);
                 failedAttempts = readIntAttribute(parser, ATTR_FAILED_ATTEMPTS, 0);
                 lastAttemptTime = readLongAttribute(parser, ATTR_LAST_RETRY_MS, 0L);
-                relatedGroupId = readIntAttribute(parser, ATTR_RELATED_GROUP_ID,
-                        UserInfo.NO_RELATED_GROUP_ID);
+                profileGroupId = readIntAttribute(parser, ATTR_PROFILE_GROUP_ID,
+                        UserInfo.NO_PROFILE_GROUP_ID);
+                if (profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
+                    // This attribute was added and renamed during development of L.
+                    // TODO Remove upgrade path by 1st May 2014
+                    profileGroupId = readIntAttribute(parser, "relatedGroupId",
+                            UserInfo.NO_PROFILE_GROUP_ID);
+                }
                 String valueString = parser.getAttributeValue(null, ATTR_PARTIAL);
                 if ("true".equals(valueString)) {
                     partial = true;
@@ -849,7 +855,7 @@
             userInfo.creationTime = creationTime;
             userInfo.lastLoggedInTime = lastLoggedInTime;
             userInfo.partial = partial;
-            userInfo.relatedGroupId = relatedGroupId;
+            userInfo.profileGroupId = profileGroupId;
             mUserRestrictions.append(id, restrictions);
             if (salt != 0L) {
                 RestrictionsPinState pinState = mRestrictionsPinStates.get(id);
@@ -964,25 +970,25 @@
         }
     }
 
-    private int getNextRelatedGroupIdLocked() {
-        int maxGroupId = UserInfo.NO_RELATED_GROUP_ID;
+    private int getNextProfileGroupIdLocked() {
+        int maxGroupId = UserInfo.NO_PROFILE_GROUP_ID;
         for (int i = 0; i < mUsers.size(); i++) {
             UserInfo ui = mUsers.valueAt(i);
-            if (maxGroupId < ui.relatedGroupId) {
-                maxGroupId = ui.relatedGroupId;
+            if (maxGroupId < ui.profileGroupId) {
+                maxGroupId = ui.profileGroupId;
             }
         }
         return maxGroupId + 1;
     }
 
     @Override
-    public UserInfo createRelatedUser(String name, int flags, int relatedUserId) {
+    public UserInfo createProfileForUser(String name, int flags, int userId) {
         checkManageUsersPermission("Only the system can create users");
-        if (relatedUserId != UserHandle.USER_OWNER) {
-            Slog.w(LOG_TAG, "Only user owner can have related users");
+        if (userId != UserHandle.USER_OWNER) {
+            Slog.w(LOG_TAG, "Only user owner can have profiles");
             return null;
         }
-        return createUserInternal(name, flags, relatedUserId);
+        return createUserInternal(name, flags, userId);
     }
 
     @Override
@@ -991,16 +997,16 @@
         return createUserInternal(name, flags, UserHandle.USER_NULL);
     }
 
-    private UserInfo createUserInternal(String name, int flags, int relatedUserId) {
+    private UserInfo createUserInternal(String name, int flags, int profileId) {
         final long ident = Binder.clearCallingIdentity();
         UserInfo userInfo = null;
         try {
             synchronized (mInstallLock) {
                 synchronized (mPackagesLock) {
-                    UserInfo relatedUser = null;
-                    if (relatedUserId != UserHandle.USER_NULL) {
-                        relatedUser = getUserInfoLocked(relatedUserId);
-                        if (relatedUser == null) return null;
+                    UserInfo profile = null;
+                    if (profileId != UserHandle.USER_NULL) {
+                        profile = getUserInfoLocked(profileId);
+                        if (profile == null) return null;
                     }
                     if (isUserLimitReachedLocked()) return null;
                     int userId = getNextAvailableIdLocked();
@@ -1013,12 +1019,12 @@
                     Environment.getUserSystemDirectory(userInfo.id).mkdirs();
                     mUsers.put(userId, userInfo);
                     writeUserListLocked();
-                    if (relatedUser != null) {
-                        if (relatedUser.relatedGroupId == UserInfo.NO_RELATED_GROUP_ID) {
-                            relatedUser.relatedGroupId = getNextRelatedGroupIdLocked();
+                    if (profile != null) {
+                        if (profile.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
+                            profile.profileGroupId = getNextProfileGroupIdLocked();
+                            writeUserLocked(profile);
                         }
-                        userInfo.relatedGroupId = relatedUser.relatedGroupId;
-                        writeUserLocked(relatedUser);
+                        userInfo.profileGroupId = profile.profileGroupId;
                     }
                     writeUserLocked(userInfo);
                     mPm.createNewUserLILPw(userId, userPath);
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
new file mode 100644
index 0000000..a83fa87
--- /dev/null
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -0,0 +1,166 @@
+/*
+ * 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.trust;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+import android.service.trust.ITrustAgentService;
+import android.service.trust.ITrustAgentServiceCallback;
+
+/**
+ * A wrapper around a TrustAgentService interface. Coordinates communication between
+ * TrustManager and the actual TrustAgent.
+ */
+public class TrustAgentWrapper {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "TrustAgentWrapper";
+
+    private static final int MSG_ENABLE_TRUST = 1;
+    private static final int MSG_REVOKE_TRUST = 2;
+    private static final int MSG_TRUST_TIMEOUT = 3;
+
+    private final TrustManagerService mTrustManagerService;
+    private final int mUserId;
+    private final Context mContext;
+    private final ComponentName mName;
+
+    private ITrustAgentService mTrustAgentService;
+
+    // Trust state
+    private boolean mTrusted;
+    private String mMessage;
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_ENABLE_TRUST:
+                    mTrusted = true;
+                    mMessage = (String) msg.obj;
+                    boolean initiatedByUser = msg.arg1 != 0;
+                    // TODO: Handle handle user initiated trust changes.
+                    mTrustManagerService.updateTrust(mUserId);
+                    break;
+                case MSG_TRUST_TIMEOUT:
+                    if (DEBUG) Slog.v(TAG, "Trust timed out : " + mName.flattenToShortString());
+                    // Fall through.
+                case MSG_REVOKE_TRUST:
+                    mTrusted = false;
+                    mMessage = null;
+                    mTrustManagerService.updateTrust(mUserId);
+                    break;
+            }
+        }
+    };
+
+    private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() {
+
+        public void enableTrust(String userMessage, long durationMs, boolean initiatedByUser) {
+            if (DEBUG) Slog.v(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs
+                        + ", initiatedByUser = " + initiatedByUser + ")");
+
+            mHandler.obtainMessage(MSG_ENABLE_TRUST, initiatedByUser ? 1 : 0, 0, userMessage)
+                    .sendToTarget();
+            if (durationMs > 0) {
+                mHandler.removeMessages(MSG_TRUST_TIMEOUT);
+                mHandler.sendEmptyMessageDelayed(MSG_TRUST_TIMEOUT, durationMs);
+            }
+        }
+
+        public void revokeTrust() {
+            if (DEBUG) Slog.v(TAG, "revokeTrust()");
+            mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
+        }
+    };
+
+    private final ServiceConnection mConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            if (DEBUG) Log.v(TAG, "TrustAgent started : " + name.flattenToString());
+            mTrustAgentService = ITrustAgentService.Stub.asInterface(service);
+            setCallback(mCallback);
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            if (DEBUG) Log.v(TAG, "TrustAgent disconnected : " + name.flattenToShortString());
+            mTrustAgentService = null;
+            mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
+        }
+    };
+
+
+    public TrustAgentWrapper(Context context, TrustManagerService trustManagerService,
+            Intent intent, UserHandle user) {
+        mContext = context;
+        mTrustManagerService = trustManagerService;
+        mUserId = user.getIdentifier();
+        mName = intent.getComponent();
+        if (!context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user)) {
+            if (DEBUG) Log.v(TAG, "can't bind to TrustAgent " + mName.flattenToShortString());
+            // TODO: retry somehow?
+        }
+    }
+
+    private void onError(Exception e) {
+        Slog.w(TAG , "Remote Exception", e);
+    }
+
+    /**
+     * @see android.service.trust.TrustAgentService#onUnlockAttempt(boolean)
+     */
+    public void onUnlockAttempt(boolean successful) {
+        try {
+            if (mTrustAgentService != null) mTrustAgentService.onUnlockAttempt(successful);
+        } catch (RemoteException e) {
+            onError(e);
+        }
+    }
+
+    private void setCallback(ITrustAgentServiceCallback callback) {
+        try {
+            if (mTrustAgentService != null) {
+                mTrustAgentService.setCallback(callback);
+            }
+        } catch (RemoteException e) {
+            onError(e);
+        }
+    }
+
+    public boolean isTrusted() {
+        return mTrusted;
+    }
+
+    public String getMessage() {
+        return mMessage;
+    }
+
+    public void unbind() {
+        if (DEBUG) Log.v(TAG, "TrustAgent unbound : " + mName.flattenToShortString());
+        mContext.unbindService(mConnection);
+    }
+}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
new file mode 100644
index 0000000..a2a49c9
--- /dev/null
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -0,0 +1,387 @@
+/*
+ * 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.trust;
+
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.server.SystemService;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.Manifest;
+import android.app.trust.ITrustListener;
+import android.app.trust.ITrustManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.service.trust.TrustAgentService;
+import android.util.ArraySet;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.util.Xml;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Manages trust agents and trust listeners.
+ *
+ * It is responsible for binding to the enabled {@link android.service.trust.TrustAgentService}s
+ * of each user and notifies them about events that are relevant to them.
+ * It start and stops them based on the value of
+ * {@link com.android.internal.widget.LockPatternUtils#getEnabledTrustAgents(int)}.
+ *
+ * It also keeps a set of {@link android.app.trust.ITrustListener}s that are notified whenever the
+ * trust state changes for any user.
+ *
+ * Trust state and the setting of enabled agents is kept per user and each user has its own
+ * instance of a {@link android.service.trust.TrustAgentService}.
+ */
+public class TrustManagerService extends SystemService {
+
+    private static final boolean DEBUG = false;
+    private static final String TAG = "TrustManagerService";
+
+    private static final Intent TRUST_AGENT_INTENT =
+            new Intent(TrustAgentService.SERVICE_INTERFACE);
+
+    private static final int MSG_REGISTER_LISTENER = 1;
+    private static final int MSG_UNREGISTER_LISTENER = 2;
+    private static final int MSG_DISPATCH_UNLOCK_ATTEMPT = 3;
+    private static final int MSG_ENABLED_AGENTS_CHANGED = 4;
+
+    private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<AgentInfo>();
+    private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<ITrustListener>();
+    private final Context mContext;
+
+    private UserManager mUserManager;
+
+    /**
+     * Cache for {@link #refreshAgentList()}
+     */
+    private final ArraySet<AgentInfo> mObsoleteAgents = new ArraySet<AgentInfo>();
+
+
+    public TrustManagerService(Context context) {
+        super(context);
+        mContext = context;
+        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.TRUST_SERVICE, mService);
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && !isSafeMode()) {
+            // Listen for package changes
+            mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
+            refreshAgentList();
+        }
+    }
+
+    // Agent management
+
+    private static final class AgentInfo {
+        CharSequence label;
+        Drawable icon;
+        ComponentName component; // service that implements ITrustAgent
+        ComponentName settings; // setting to launch to modify agent.
+        TrustAgentWrapper agent;
+        int userId;
+
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof AgentInfo)) {
+                return false;
+            }
+            AgentInfo o = (AgentInfo) other;
+            return component.equals(o.component) && userId == o.userId;
+        }
+
+        @Override
+        public int hashCode() {
+            return component.hashCode() * 31 + userId;
+        }
+    }
+
+    private void updateTrustAll() {
+        List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
+        for (UserInfo userInfo : userInfos) {
+            updateTrust(userInfo.id);
+        }
+    }
+
+    public void updateTrust(int userId) {
+        dispatchOnTrustChanged(aggregateIsTrusted(userId), userId);
+    }
+
+    protected void refreshAgentList() {
+        if (DEBUG) Slog.d(TAG, "refreshAgentList()");
+        PackageManager pm = mContext.getPackageManager();
+
+        List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
+        LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
+
+        mObsoleteAgents.clear();
+        mObsoleteAgents.addAll(mActiveAgents);
+
+        for (UserInfo userInfo : userInfos) {
+            List<ComponentName> enabledAgents = lockPatternUtils.getEnabledTrustAgents(userInfo.id);
+            if (enabledAgents == null) {
+                continue;
+            }
+            List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(TRUST_AGENT_INTENT,
+                    PackageManager.GET_META_DATA, userInfo.id);
+            for (ResolveInfo resolveInfo : resolveInfos) {
+                if (resolveInfo.serviceInfo == null) continue;
+                ComponentName name = getComponentName(resolveInfo);
+                if (!enabledAgents.contains(name)) continue;
+
+                AgentInfo agentInfo = new AgentInfo();
+                agentInfo.component = name;
+                agentInfo.userId = userInfo.id;
+                if (!mActiveAgents.contains(agentInfo)) {
+                    agentInfo.label = resolveInfo.loadLabel(pm);
+                    agentInfo.icon = resolveInfo.loadIcon(pm);
+                    agentInfo.settings = getSettingsComponentName(pm, resolveInfo);
+                    agentInfo.agent = new TrustAgentWrapper(mContext, this,
+                            new Intent().setComponent(name), userInfo.getUserHandle());
+                    mActiveAgents.add(agentInfo);
+                } else {
+                    mObsoleteAgents.remove(agentInfo);
+                }
+            }
+        }
+
+        boolean trustMayHaveChanged = false;
+        for (int i = 0; i < mObsoleteAgents.size(); i++) {
+            AgentInfo info = mActiveAgents.valueAt(i);
+            if (info.agent.isTrusted()) {
+                trustMayHaveChanged = true;
+            }
+            info.agent.unbind();
+            mActiveAgents.remove(info);
+        }
+
+        if (trustMayHaveChanged) {
+            updateTrustAll();
+        }
+    }
+
+    private ComponentName getSettingsComponentName(PackageManager pm, ResolveInfo resolveInfo) {
+        if (resolveInfo == null || resolveInfo.serviceInfo == null
+                || resolveInfo.serviceInfo.metaData == null) return null;
+        String cn = null;
+        XmlResourceParser parser = null;
+        Exception caughtException = null;
+        try {
+            parser = resolveInfo.serviceInfo.loadXmlMetaData(pm,
+                    TrustAgentService.TRUST_AGENT_META_DATA);
+            if (parser == null) {
+                Slog.w(TAG, "Can't find " + TrustAgentService.TRUST_AGENT_META_DATA + " meta-data");
+                return null;
+            }
+            Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo);
+            AttributeSet attrs = Xml.asAttributeSet(parser);
+            int type;
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                    && type != XmlPullParser.START_TAG) {
+                // Drain preamble.
+            }
+            String nodeName = parser.getName();
+            if (!"trust_agent".equals(nodeName)) {
+                Slog.w(TAG, "Meta-data does not start with trust_agent tag");
+                return null;
+            }
+            TypedArray sa = res
+                    .obtainAttributes(attrs, com.android.internal.R.styleable.TrustAgent);
+            cn = sa.getString(com.android.internal.R.styleable.TrustAgent_settingsActivity);
+            sa.recycle();
+        } catch (PackageManager.NameNotFoundException e) {
+            caughtException = e;
+        } catch (IOException e) {
+            caughtException = e;
+        } catch (XmlPullParserException e) {
+            caughtException = e;
+        } finally {
+            if (parser != null) parser.close();
+        }
+        if (caughtException != null) {
+            Slog.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException);
+            return null;
+        }
+        if (cn == null) {
+            return null;
+        }
+        if (cn.indexOf('/') < 0) {
+            cn = resolveInfo.serviceInfo.packageName + "/" + cn;
+        }
+        return ComponentName.unflattenFromString(cn);
+    }
+
+    private ComponentName getComponentName(ResolveInfo resolveInfo) {
+        if (resolveInfo == null || resolveInfo.serviceInfo == null) return null;
+        return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
+    }
+
+    // Agent dispatch and aggregation
+
+    private boolean aggregateIsTrusted(int userId) {
+        for (int i = 0; i < mActiveAgents.size(); i++) {
+            AgentInfo info = mActiveAgents.valueAt(i);
+            if (info.userId == userId) {
+                if (info.agent.isTrusted()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private void dispatchUnlockAttempt(boolean successful, int userId) {
+        for (int i = 0; i < mActiveAgents.size(); i++) {
+            AgentInfo info = mActiveAgents.valueAt(i);
+            if (info.userId == userId) {
+                info.agent.onUnlockAttempt(successful);
+            }
+        }
+    }
+
+    // Listeners
+
+    private void addListener(ITrustListener listener) {
+        for (int i = 0; i < mTrustListeners.size(); i++) {
+            if (mTrustListeners.get(i).asBinder() == listener.asBinder()) {
+                return;
+            }
+        }
+        mTrustListeners.add(listener);
+    }
+
+    private void removeListener(ITrustListener listener) {
+        for (int i = 0; i < mTrustListeners.size(); i++) {
+            if (mTrustListeners.get(i).asBinder() == listener.asBinder()) {
+                mTrustListeners.get(i);
+                return;
+            }
+        }
+    }
+
+    private void dispatchOnTrustChanged(boolean enabled, int userId) {
+        for (int i = 0; i < mTrustListeners.size(); i++) {
+            try {
+                mTrustListeners.get(i).onTrustChanged(enabled, userId);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Exception while notifying TrustListener. Removing listener.", e);
+                mTrustListeners.get(i);
+                i--;
+            }
+        }
+    }
+
+    // Plumbing
+
+    private final IBinder mService = new ITrustManager.Stub() {
+        @Override
+        public void reportUnlockAttempt(boolean authenticated, int userId) throws RemoteException {
+            enforceReportPermission();
+            mHandler.obtainMessage(MSG_DISPATCH_UNLOCK_ATTEMPT, authenticated ? 1 : 0, userId)
+                    .sendToTarget();
+        }
+
+        @Override
+        public void reportEnabledTrustAgentsChanged(int userId) throws RemoteException {
+            enforceReportPermission();
+            // coalesce refresh messages.
+            mHandler.removeMessages(MSG_ENABLED_AGENTS_CHANGED);
+            mHandler.sendEmptyMessage(MSG_ENABLED_AGENTS_CHANGED);
+        }
+
+        @Override
+        public void registerTrustListener(ITrustListener trustListener) throws RemoteException {
+            enforceListenerPermission();
+            mHandler.obtainMessage(MSG_REGISTER_LISTENER, trustListener).sendToTarget();
+        }
+
+        @Override
+        public void unregisterTrustListener(ITrustListener trustListener) throws RemoteException {
+            enforceListenerPermission();
+            mHandler.obtainMessage(MSG_UNREGISTER_LISTENER, trustListener).sendToTarget();
+        }
+
+        private void enforceReportPermission() {
+            mContext.enforceCallingPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE,
+                    "reporting trust events");
+        }
+
+        private void enforceListenerPermission() {
+            mContext.enforceCallingPermission(Manifest.permission.TRUST_LISTENER,
+                    "register trust listener");
+        }
+    };
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_REGISTER_LISTENER:
+                    addListener((ITrustListener) msg.obj);
+                    break;
+                case MSG_UNREGISTER_LISTENER:
+                    removeListener((ITrustListener) msg.obj);
+                    break;
+                case MSG_DISPATCH_UNLOCK_ATTEMPT:
+                    dispatchUnlockAttempt(msg.arg1 != 0, msg.arg2);
+                    break;
+                case MSG_ENABLED_AGENTS_CHANGED:
+                    refreshAgentList();
+                    break;
+            }
+        }
+    };
+
+    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
+        @Override
+        public void onSomePackagesChanged() {
+            refreshAgentList();
+        }
+
+        @Override
+        public boolean onPackageChanged(String packageName, int uid, String[] components) {
+            // We're interested in all changes, even if just some components get enabled / disabled.
+            return true;
+        }
+    };
+}
diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java
new file mode 100644
index 0000000..fbfca93
--- /dev/null
+++ b/services/core/java/com/android/server/wm/CircularDisplayMask.java
@@ -0,0 +1,110 @@
+/*
+ * 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.wm;
+
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.util.Log;
+import android.view.Display;
+import android.view.Surface;
+import android.view.Surface.OutOfResourcesException;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+
+class CircularDisplayMask {
+    private static final String TAG = "CircularDisplayMask";
+
+    private static final int STROKE_WIDTH = 2;
+
+    private final SurfaceControl mSurfaceControl;
+    private final Surface mSurface = new Surface();
+    private int mLastDW;
+    private int mLastDH;
+    private boolean mDrawNeeded;
+    private Paint mPaint;
+
+    public CircularDisplayMask(Display display, SurfaceSession session, int zOrder) {
+        SurfaceControl ctrl = null;
+        try {
+            ctrl = new SurfaceControl(session, "CircularDisplayMask",
+                320, 290, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
+            ctrl.setLayerStack(display.getLayerStack());
+            ctrl.setLayer(zOrder);
+            ctrl.setPosition(0, 0);
+            ctrl.show();
+            mSurface.copyFrom(ctrl);
+        } catch (OutOfResourcesException e) {
+        }
+        mSurfaceControl = ctrl;
+        mDrawNeeded = true;
+        mPaint = new Paint();
+        mPaint.setAntiAlias(true);
+        mPaint.setStyle(Paint.Style.STROKE);
+        mPaint.setColor(Color.BLACK);
+        mPaint.setStrokeWidth(STROKE_WIDTH);
+    }
+
+    private void drawIfNeeded() {
+        if (!mDrawNeeded) {
+            return;
+        }
+        mDrawNeeded = false;
+
+        Rect dirty = new Rect(0, 0, mLastDW, mLastDH);
+        Canvas c = null;
+        try {
+            c = mSurface.lockCanvas(dirty);
+        } catch (IllegalArgumentException e) {
+        } catch (Surface.OutOfResourcesException e) {
+        }
+        if (c == null) {
+            return;
+        }
+        c.drawCircle(160, 160, 160, mPaint);
+
+        mSurface.unlockCanvasAndPost(c);
+    }
+
+    // Note: caller responsible for being inside
+    // Surface.openTransaction() / closeTransaction()
+    public void setVisibility(boolean on) {
+        if (mSurfaceControl == null) {
+            return;
+        }
+        drawIfNeeded();
+        if (on) {
+            mSurfaceControl.show();
+        } else {
+            mSurfaceControl.hide();
+        }
+    }
+
+    void positionSurface(int dw, int dh) {
+        if (mLastDW == dw && mLastDH == dh) {
+            return;
+        }
+        mLastDW = dw;
+        mLastDH = dh;
+        mSurfaceControl.setSize(dw, dh);
+        mDrawNeeded = true;
+    }
+
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0558b5a..2e5b8de 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -285,6 +285,8 @@
     private static final String DENSITY_OVERRIDE = "ro.config.density_override";
     private static final String SIZE_OVERRIDE = "ro.config.size_override";
 
+    private static final String SCREEN_CIRCULAR = "ro.display.circular";
+
     private static final int MAX_SCREENSHOT_RETRIES = 3;
 
     final private KeyguardDisableHandler mKeyguardDisableHandler;
@@ -302,14 +304,14 @@
 
     /**
      * Current user when multi-user is enabled. Don't show windows of
-     * non-current user. Also see mRelatedUserIds.
+     * non-current user. Also see mCurrentProfileIds.
      */
     int mCurrentUserId;
     /**
-     * Users related to the current user. These are also allowed to show windows
+     * Users that are profiles of the current user. These are also allowed to show windows
      * on the current user.
      */
-    int[] mRelatedUserIds = new int[0];
+    int[] mCurrentProfileIds = new int[0];
 
     final Context mContext;
 
@@ -422,6 +424,7 @@
     final SurfaceSession mFxSession;
     Watermark mWatermark;
     StrictModeFlash mStrictModeFlash;
+    CircularDisplayMask mCircularDisplayMask;
     FocusedStackFrame mFocusedStackFrame;
 
     int mFocusedStackLayer;
@@ -819,6 +822,7 @@
         }
 
         LocalServices.addService(WindowManagerInternal.class, new LocalService());
+        showCircularDisplayMaskIfNeeded();
     }
 
     public InputMonitor getInputMonitor() {
@@ -920,6 +924,10 @@
         final IWindow client = win.mClient;
         final WindowToken token = win.mToken;
         final DisplayContent displayContent = win.getDisplayContent();
+        if (displayContent == null) {
+            // It doesn't matter this display is going away.
+            return 0;
+        }
 
         final WindowList windows = win.getWindowList();
         final int N = windows.size();
@@ -1097,6 +1105,9 @@
     private void addAttachedWindowToListLocked(final WindowState win, boolean addToToken) {
         final WindowToken token = win.mToken;
         final DisplayContent displayContent = win.getDisplayContent();
+        if (displayContent == null) {
+            return;
+        }
         final WindowState attached = win.mAttachedWindow;
 
         WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent);
@@ -2254,6 +2265,11 @@
                 return WindowManagerGlobal.ADD_APP_EXITING;
             }
 
+            if (win.getDisplayContent() == null) {
+                Slog.w(TAG, "Adding window to Display that has been removed.");
+                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
+            }
+
             mPolicy.adjustWindowParamsLw(win.mAttrs);
             win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
 
@@ -2743,7 +2759,7 @@
             return;
         }
 
-        final DisplayInfo displayInfo = window.getDisplayContent().getDisplayInfo();
+        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
         final RectF dispRect = new RectF(0, 0,
                 displayInfo.logicalWidth, displayInfo.logicalHeight);
         matrix.mapRect(dispRect);
@@ -5213,16 +5229,16 @@
         ShutdownThread.rebootSafeMode(mContext, confirm);
     }
 
-    public void updateRelatedUserIds(final int[] relatedUserIds) {
+    public void setCurrentProfileIds(final int[] currentProfileIds) {
         synchronized (mWindowMap) {
-            mRelatedUserIds = relatedUserIds;
+            mCurrentProfileIds = currentProfileIds;
         }
     }
 
-    public void setCurrentUser(final int newUserId, final int[] relatedUserIds) {
+    public void setCurrentUser(final int newUserId, final int[] currentProfileIds) {
         synchronized (mWindowMap) {
             mCurrentUserId = newUserId;
-            mRelatedUserIds = relatedUserIds;
+            mCurrentProfileIds = currentProfileIds;
             mAppTransition.setCurrentUser(newUserId);
             mPolicy.setCurrentUserLw(newUserId);
 
@@ -5238,10 +5254,9 @@
     }
 
     /* Called by WindowState */
-    boolean isRelatedToOrCurrentUserLocked(int userId) {
-        if (userId == mCurrentUserId) return true;
-        for (int i = 0; i < mRelatedUserIds.length; i++) {
-            if (mRelatedUserIds[i] == userId) return true;
+    boolean isCurrentProfileLocked(int userId) {
+        for (int i = 0; i < mCurrentProfileIds.length; i++) {
+            if (mCurrentProfileIds[i] == userId) return true;
         }
         return false;
     }
@@ -5471,6 +5486,37 @@
         }
     }
 
+    public void showCircularDisplayMaskIfNeeded() {
+        if (SystemProperties.getBoolean(SCREEN_CIRCULAR, false)) {
+            mH.sendMessage(mH.obtainMessage(H.SHOW_DISPLAY_MASK));
+        }
+    }
+
+    public void showCircularMask() {
+        synchronized(mWindowMap) {
+
+            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+                    ">>> OPEN TRANSACTION showDisplayMask");
+            SurfaceControl.openTransaction();
+            try {
+                // TODO(multi-display): support multiple displays
+                if (mCircularDisplayMask == null) {
+                    mCircularDisplayMask = new CircularDisplayMask(
+                            getDefaultDisplayContentLocked().getDisplay(),
+                            mFxSession,
+                            mPolicy.windowTypeToLayerLw(
+                                    WindowManager.LayoutParams.TYPE_POINTER)
+                                    * TYPE_LAYER_MULTIPLIER + 10);
+                }
+                mCircularDisplayMask.setVisibility(true);
+            } finally {
+                SurfaceControl.closeTransaction();
+                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+                        "<<< CLOSE TRANSACTION showDisplayMask");
+            }
+        }
+    }
+
     // TODO: more accounting of which pid(s) turned it on, keep count,
     // only allow disables from pids which have count on, etc.
     @Override
@@ -7095,6 +7141,8 @@
 
         public static final int REMOVE_STARTING_TIMEOUT = 33;
 
+        public static final int SHOW_DISPLAY_MASK = 34;
+
         @Override
         public void handleMessage(Message msg) {
             if (DEBUG_WINDOW_TRACE) {
@@ -7490,6 +7538,11 @@
                     break;
                 }
 
+                case SHOW_DISPLAY_MASK: {
+                    showCircularMask();
+                    break;
+                }
+
                 case DO_ANIMATION_CALLBACK: {
                     try {
                         ((IRemoteCallback)msg.obj).sendResult(null);
@@ -8963,6 +9016,9 @@
             if (mStrictModeFlash != null) {
                 mStrictModeFlash.positionSurface(defaultDw, defaultDh);
             }
+            if (mCircularDisplayMask != null) {
+                mCircularDisplayMask.positionSurface(defaultDw, defaultDh);
+            }
 
             boolean focusDisplayed = false;
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 2c0e99e..dff75ef 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1249,7 +1249,7 @@
         }
 
         return win.mShowToOwnerOnly
-                && !mService.isRelatedToOrCurrentUserLocked(UserHandle.getUserId(win.mOwnerUid));
+                && !mService.isCurrentProfileLocked(UserHandle.getUserId(win.mOwnerUid));
     }
 
     private static void applyInsets(Region outRegion, Rect frame, Rect inset) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 6b3c368..3c9d53e 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -176,9 +176,15 @@
         mAnimator = service.mAnimator;
         mPolicy = service.mPolicy;
         mContext = service.mContext;
-        final DisplayInfo displayInfo = win.getDisplayContent().getDisplayInfo();
-        mAnimDw = displayInfo.appWidth;
-        mAnimDh = displayInfo.appHeight;
+        final DisplayContent displayContent = win.getDisplayContent();
+        if (displayContent != null) {
+            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+            mAnimDw = displayInfo.appWidth;
+            mAnimDh = displayInfo.appHeight;
+        } else {
+            Slog.w(TAG, "WindowStateAnimator ctor: Display has been removed");
+            // This is checked on return and dealt with.
+        }
 
         mWin = win;
         mAttachedWinAnimator = win.mAttachedWindow == null
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
index 6170c09..61edda8 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
@@ -63,24 +63,21 @@
     void initialize();
 
     // initialize individual logical device.
-    int initLogicalDevice(int type);
-    void releaseLogicalDevice(int type);
+    cec_logical_address_t initLogicalDevice(cec_device_type_t type);
+    void releaseLogicalDevice(cec_device_type_t type);
 
-    cec_logical_address_t getLogicalAddress(int deviceType);
+    cec_logical_address_t getLogicalAddress(cec_device_type_t deviceType);
+    uint16_t getPhysicalAddress();
     int getDeviceType(cec_logical_address_t addr);
     void queueMessage(const MessageEntry& message);
     void queueOutgoingMessage(const cec_message_t& message);
     void sendReportPhysicalAddress();
     void sendActiveSource(cec_logical_address_t srcAddr);
-    void sendInactiveSource(cec_logical_address_t srcAddr);
-    void sendImageViewOn(cec_logical_address_t srcAddr);
-    void sendTextViewOn(cec_logical_address_t srcAddr);
-    void sendGiveDevicePowerStatus(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr);
     void sendFeatureAbort(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr,
             int opcode, int reason);
     void sendCecVersion(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr,
             int version);
-    void sendDeviceVendorID(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr);
+    void sendDeviceVendorId(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr);
     void sendGiveDeviceVendorID(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr);
     void sendSetOsdName(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr,
             const char* name, size_t len);
@@ -104,6 +101,7 @@
     static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
 
     void updatePhysicalAddress();
+    void updateLogicalAddress();
     void dispatchMessage(const MessageEntry& message);
     void processIncomingMessage(const cec_message_t& msg);
 
@@ -147,7 +145,7 @@
     };
 
     // device type -> logical address mapping
-    std::map<int, cec_logical_address_t> mLogicalDevices;
+    std::map<cec_device_type_t, cec_logical_address_t> mLogicalDevices;
 
     hdmi_cec_device_t* mDevice;
     jobject mCallbacksObj;
@@ -173,6 +171,10 @@
     updatePhysicalAddress();
 }
 
+uint16_t HdmiCecHandler::getPhysicalAddress() {
+    return mPhysicalAddress;
+}
+
 void HdmiCecHandler::updatePhysicalAddress() {
     uint16_t addr;
     if (!mDevice->get_physical_address(mDevice, &addr)) {
@@ -182,7 +184,17 @@
     }
 }
 
-int HdmiCecHandler::initLogicalDevice(int type) {
+void HdmiCecHandler::updateLogicalAddress() {
+    std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.begin();
+    for (; it != mLogicalDevices.end(); ++it) {
+        cec_logical_address_t addr;
+        if (!mDevice->get_logical_address(mDevice, it->first, &addr)) {
+            it->second = addr;
+        }
+    }
+}
+
+cec_logical_address_t HdmiCecHandler::initLogicalDevice(cec_device_type_t type) {
     cec_logical_address_t addr;
     int res = mDevice->allocate_logical_address(mDevice, type, &addr);
 
@@ -190,21 +202,21 @@
         ALOGE("Logical Address Allocation failed: %d", res);
     } else {
         ALOGV("Logical Address Allocation success: %d", addr);
-        mLogicalDevices.insert(std::pair<int, cec_logical_address_t>(type, addr));
+        mLogicalDevices.insert(std::pair<cec_device_type_t, cec_logical_address_t>(type, addr));
     }
     return addr;
 }
 
-void HdmiCecHandler::releaseLogicalDevice(int type) {
-    std::map<int, cec_logical_address_t>::iterator it = mLogicalDevices.find(type);
+void HdmiCecHandler::releaseLogicalDevice(cec_device_type_t type) {
+    std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.find(type);
     if (it != mLogicalDevices.end()) {
         mLogicalDevices.erase(it);
     }
     // TODO: remove the address monitored in HAL as well.
 }
 
-cec_logical_address_t HdmiCecHandler::getLogicalAddress(int mDevicetype) {
-    std::map<int, cec_logical_address_t>::iterator it = mLogicalDevices.find(mDevicetype);
+cec_logical_address_t HdmiCecHandler::getLogicalAddress(cec_device_type_t type) {
+    std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.find(type);
     if (it != mLogicalDevices.end()) {
         return it->second;
     }
@@ -212,7 +224,7 @@
 }
 
 int HdmiCecHandler::getDeviceType(cec_logical_address_t addr) {
-    std::map<int, cec_logical_address_t>::iterator it = mLogicalDevices.begin();
+    std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.begin();
     for (; it != mLogicalDevices.end(); ++it) {
         if (it->second == addr) {
             return it->first;
@@ -245,14 +257,15 @@
     }
 
     // Report physical address for each logical one hosted in it.
-    std::map<int, cec_logical_address_t>::iterator it = mLogicalDevices.begin();
+    std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.begin();
     while (it != mLogicalDevices.end()) {
         cec_message_t msg;
         msg.initiator = it->second;  // logical address
         msg.destination = CEC_ADDR_BROADCAST;
         msg.length = 4;
         msg.body[0] = CEC_MESSAGE_REPORT_PHYSICAL_ADDRESS;
-        std::memcpy(msg.body + 1, &mPhysicalAddress, 2);
+        msg.body[1] = (mPhysicalAddress >> 8) & 0xff;
+        msg.body[2] = mPhysicalAddress & 0xff;
         msg.body[3] = it->first;  // device type
         queueOutgoingMessage(msg);
         ++it;
@@ -269,47 +282,8 @@
     msg.destination = CEC_ADDR_BROADCAST;
     msg.length = 3;
     msg.body[0] = CEC_MESSAGE_ACTIVE_SOURCE;
-    std::memcpy(msg.body + 1, &mPhysicalAddress, 2);
-    queueOutgoingMessage(msg);
-}
-
-void HdmiCecHandler::sendInactiveSource(cec_logical_address_t srcAddr) {
-    cec_message_t msg;
-    msg.initiator = srcAddr;
-    msg.destination = CEC_ADDR_TV;
-    msg.length = 3;
-    msg.body[0] = CEC_MESSAGE_INACTIVE_SOURCE;
-    if (mPhysicalAddress != INVALID_PHYSICAL_ADDRESS) {
-        std::memcpy(msg.body + 1, &mPhysicalAddress, 2);
-        queueOutgoingMessage(msg);
-    }
-}
-
-void HdmiCecHandler::sendImageViewOn(cec_logical_address_t srcAddr) {
-    cec_message_t msg;
-    msg.initiator = srcAddr;
-    msg.destination = CEC_ADDR_TV;
-    msg.length = 1;
-    msg.body[0] = CEC_MESSAGE_IMAGE_VIEW_ON;
-    queueOutgoingMessage(msg);
-}
-
-void HdmiCecHandler::sendTextViewOn(cec_logical_address_t srcAddr) {
-    cec_message_t msg;
-    msg.initiator = srcAddr;
-    msg.destination = CEC_ADDR_TV;
-    msg.length = 1;
-    msg.body[0] = CEC_MESSAGE_TEXT_VIEW_ON;
-    queueOutgoingMessage(msg);
-}
-
-void HdmiCecHandler::sendGiveDevicePowerStatus(cec_logical_address_t srcAddr,
-        cec_logical_address_t dstAddr) {
-    cec_message_t msg;
-    msg.initiator = srcAddr;
-    msg.destination = dstAddr;
-    msg.length = 1;
-    msg.body[0] = CEC_MESSAGE_GIVE_DEVICE_POWER_STATUS;
+    msg.body[1] = (mPhysicalAddress >> 8) & 0xff;
+    msg.body[2] = mPhysicalAddress & 0xff;
     queueOutgoingMessage(msg);
 }
 
@@ -346,7 +320,7 @@
     queueOutgoingMessage(msg);
 }
 
-void HdmiCecHandler::sendDeviceVendorID(cec_logical_address_t srcAddr,
+void HdmiCecHandler::sendDeviceVendorId(cec_logical_address_t srcAddr,
         cec_logical_address_t dstAddr) {
     cec_message_t msg;
     msg.initiator = srcAddr;
@@ -355,7 +329,9 @@
     msg.body[0] = CEC_MESSAGE_DEVICE_VENDOR_ID;
     uint32_t vendor_id;
     mDevice->get_vendor_id(mDevice, &vendor_id);
-    std::memcpy(msg.body + 1, &vendor_id, 3);
+    msg.body[1] = (vendor_id >> 16) & 0xff;
+    msg.body[2] = (vendor_id >> 8) & 0xff;
+    msg.body[3] = vendor_id & 0xff;
     queueOutgoingMessage(msg);
 }
 
@@ -437,9 +413,8 @@
         mMessageQueue.pop_front();
         bool connected = entry.second.hotplug.connected;
         if (connected) {
-            // TODO: Update logical addresses as well, since they also could have
-            // changed while the cable was disconnected.
             updatePhysicalAddress();
+            updateLogicalAddress();
         }
         propagateHotplug(connected);
     }
@@ -460,6 +435,9 @@
         handleGetCECVersion(msg);
     } else if (opcode == CEC_MESSAGE_GET_MENU_LANGUAGE) {
         handleGetMenuLanguage(msg);
+    } else if (opcode == CEC_MESSAGE_ABORT) {
+        // Compliance testing requires that abort message be responded with feature abort.
+        sendFeatureAbort(msg.destination, msg.initiator, msg.body[0], ABORT_REFUSED);
     } else {
         if (precheckMessage(msg)) {
             propagateMessage(msg);
@@ -480,8 +458,7 @@
             (opcode == CEC_MESSAGE_ACTIVE_SOURCE ||
              opcode == CEC_MESSAGE_SET_STREAM_PATH ||
              opcode == CEC_MESSAGE_INACTIVE_SOURCE)) {
-        uint16_t senderAddr;
-        std::memcpy(&senderAddr, &msg.body[1], 2);
+        uint16_t senderAddr = (msg.body[1] << 8) + msg.body[2];
         if (senderAddr == mPhysicalAddress) {
             return false;
         }
@@ -521,7 +498,7 @@
     jint activeDeviceType = env->CallIntMethod(mCallbacksObj,
             gHdmiCecServiceClassInfo.getActiveSource);
     if (activeDeviceType != INACTIVE_DEVICE_TYPE) {
-        sendActiveSource(getLogicalAddress(activeDeviceType));
+        sendActiveSource(getLogicalAddress(static_cast<cec_device_type_t>(activeDeviceType)));
     }
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
 }
@@ -542,7 +519,7 @@
 }
 
 void HdmiCecHandler::handleGiveDeviceVendorID(const cec_message_t& msg) {
-    sendDeviceVendorID(msg.destination, msg.initiator);
+    sendDeviceVendorId(msg.destination, msg.initiator);
 }
 
 void HdmiCecHandler::handleGetCECVersion(const cec_message_t& msg) {
@@ -596,64 +573,34 @@
 static void nativeSendMessage(JNIEnv* env, jclass clazz, jlong handlerPtr, jint deviceType,
         jint dstAddr, jint opcode, jbyteArray params) {
     HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
-    cec_logical_address_t srcAddr = handler->getLogicalAddress(deviceType);
+    cec_logical_address_t srcAddr = handler->getLogicalAddress(
+            static_cast<cec_device_type_t>(deviceType));
     jsize len = env->GetArrayLength(params);
     ScopedByteArrayRO paramsPtr(env, params);
     cec_message_t message;
     message.initiator = srcAddr;
     message.destination = static_cast<cec_logical_address_t>(dstAddr);
-    message.length = len + 1;
+    message.length = min(len + 1, CEC_MESSAGE_BODY_MAX_LENGTH);
     message.body[0] = opcode;
-    std::memcpy(message.body + 1, paramsPtr.get(), len);
+    std::memcpy(message.body + 1, paramsPtr.get(), message.length - 1);
     handler->sendCecMessage(message);
 }
 
-static int nativeAllocateLogicalAddress(JNIEnv* env, jclass clazz, jlong handlerPtr,
+static jint nativeAllocateLogicalAddress(JNIEnv* env, jclass clazz, jlong handlerPtr,
         jint deviceType) {
     HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
-    return handler->initLogicalDevice(deviceType);
+    return handler->initLogicalDevice(static_cast<cec_device_type_t>(deviceType));
 }
 
 static void nativeRemoveLogicalAddress(JNIEnv* env, jclass clazz, jlong handlerPtr,
        jint deviceType) {
     HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
-    return handler->releaseLogicalDevice(deviceType);
+    return handler->releaseLogicalDevice(static_cast<cec_device_type_t>(deviceType));
 }
 
-static void nativeSendActiveSource(JNIEnv* env, jclass clazz, jlong handlerPtr,
-        jint deviceType) {
+static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz, jlong handlerPtr) {
     HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
-    cec_logical_address_t srcAddr = handler->getLogicalAddress(deviceType);
-    handler->sendActiveSource(srcAddr);
-}
-
-static void nativeSendInactiveSource(JNIEnv* env, jclass clazz, jlong handlerPtr,
-        jint deviceType) {
-    HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
-    cec_logical_address_t srcAddr = handler->getLogicalAddress(deviceType);
-    handler->sendInactiveSource(srcAddr);
-}
-
-static void nativeSendImageViewOn(JNIEnv* env, jclass clazz, jlong handlerPtr,
-        jint deviceType) {
-    HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
-    cec_logical_address_t srcAddr = handler->getLogicalAddress(deviceType);
-    handler->sendImageViewOn(srcAddr);
-}
-
-static void nativeSendTextViewOn(JNIEnv* env, jclass clazz, jlong handlerPtr,
-        jint deviceType) {
-    HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
-    cec_logical_address_t srcAddr = handler->getLogicalAddress(deviceType);
-    handler->sendTextViewOn(srcAddr);
-}
-
-static void nativeSendGiveDevicePowerStatus(JNIEnv* env, jclass clazz, jlong handlerPtr,
-        jint deviceType, jint destination) {
-    HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
-    cec_logical_address_t srcAddr = handler->getLogicalAddress(deviceType);
-    cec_logical_address_t dstAddr = static_cast<cec_logical_address_t>(destination);
-    handler->sendGiveDevicePowerStatus(srcAddr, dstAddr);
+    return handler->getPhysicalAddress();
 }
 
 static JNINativeMethod sMethods[] = {
@@ -666,16 +613,8 @@
             (void *)nativeAllocateLogicalAddress },
     { "nativeRemoveLogicalAddress", "(JI)V",
             (void *)nativeRemoveLogicalAddress },
-    { "nativeSendActiveSource", "(JI)V",
-            (void *)nativeSendActiveSource },
-    { "nativeSendInactiveSource", "(JI)V",
-            (void *)nativeSendInactiveSource },
-    { "nativeSendImageViewOn", "(JI)V",
-            (void *)nativeSendImageViewOn },
-    { "nativeSendTextViewOn", "(JI)V",
-            (void *)nativeSendTextViewOn },
-    { "nativeSendGiveDevicePowerStatus", "(JII)V",
-            (void *)nativeSendGiveDevicePowerStatus }
+    { "nativeGetPhysicalAddress", "(J)I",
+            (void *)nativeGetPhysicalAddress },
 };
 
 #define CLASS_PATH "com/android/server/hdmi/HdmiCecService"
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f186b2c..983ca2d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -170,7 +170,7 @@
         int mActivePasswordNonLetter = 0;
         int mFailedPasswordAttempts = 0;
 
-        int mUserHandle;;
+        int mUserHandle;
         int mPasswordOwner = -1;
         long mLastMaximumTimeToLock = -1;
 
@@ -722,6 +722,10 @@
         final int callingUid = Binder.getCallingUid();
         final int userHandle = UserHandle.getUserId(callingUid);
         final DevicePolicyData policy = getUserData(userHandle);
+
+        List<ActiveAdmin> candidates = new ArrayList<ActiveAdmin>();
+
+        // Build a list of admins for this uid matching the given ComponentName
         if (who != null) {
             ActiveAdmin admin = policy.mAdminMap.get(who);
             if (admin == null) {
@@ -731,22 +735,43 @@
                 throw new SecurityException("Admin " + who + " is not owned by uid "
                         + Binder.getCallingUid());
             }
-            if (!admin.info.usesPolicy(reqPolicy)) {
-                throw new SecurityException("Admin " + admin.info.getComponent()
-                        + " did not specify uses-policy for: "
-                        + admin.info.getTagForPolicy(reqPolicy));
-            }
-            return admin;
+            candidates.add(admin);
         } else {
-            final int N = policy.mAdminList.size();
-            for (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
+            for (ActiveAdmin admin : policy.mAdminList) {
+                if (admin.getUid() == callingUid) {
+                    candidates.add(admin);
+                }
+            }
+        }
+
+        // Try to find an admin which can use reqPolicy
+        for (ActiveAdmin admin : candidates) {
+            boolean ownsDevice = isDeviceOwner(admin.info.getPackageName());
+            boolean ownsProfile = (getProfileOwner(userHandle) != null
+                    && getProfileOwner(userHandle).equals(admin.info.getPackageName()));
+
+            if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
+                if (ownsDevice) {
+                    return admin;
+                }
+            } else if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
+                if (ownsDevice || ownsProfile) {
+                    return admin;
+                }
+            } else {
+                if (admin.info.usesPolicy(reqPolicy)) {
                     return admin;
                 }
             }
+        }
+
+        if (who != null) {
+            throw new SecurityException("Admin " + candidates.get(0).info.getComponent()
+                    + " did not specify uses-policy for: "
+                    + candidates.get(0).info.getTagForPolicy(reqPolicy));
+        } else {
             throw new SecurityException("No active admin owned by uid "
-                    + Binder.getCallingUid() + " for policy #" + reqPolicy);
+                    + Binder.getCallingUid() + " for policy:" + reqPolicy);
         }
     }
 
@@ -2966,64 +2991,41 @@
         }
     }
 
-    private boolean isProfileOwner(String packageName, int userId) {
-        String profileOwnerPackage = getProfileOwner(userId);
-        // TODO: make public and connect with isProfileOwnerApp in DPM
-        return profileOwnerPackage != null && profileOwnerPackage.equals(packageName);
-    }
-
-    public void addPersistentPreferredActivity(ComponentName admin, IntentFilter filter,
+    public void addPersistentPreferredActivity(ComponentName who, IntentFilter filter,
             ComponentName activity) {
-        int callingUserId = UserHandle.getCallingUserId();
-        Slog.d(LOG_TAG,"called by user " + callingUserId);
         synchronized (this) {
-            ActiveAdmin aa = getActiveAdminUncheckedLocked(admin, callingUserId);
-            if (aa == null) {
-                throw new SecurityException("No active admin " + admin);
-            } else {
-                if (isProfileOwner(admin.getPackageName(), callingUserId)
-                        || isDeviceOwner(admin.getPackageName())) {
-                    IPackageManager pm = AppGlobals.getPackageManager();
-                    long id = Binder.clearCallingIdentity();
-                    try {
-                        pm.addPersistentPreferredActivity(filter, activity, callingUserId);
-                    } catch (RemoteException re) {
-                        // Shouldn't happen
-                    } finally {
-                        restoreCallingIdentity(id);
-                    }
-                } else {
-                    throw new SecurityException("Admin " + admin +
-                            "is not device owner or profile owner" );
-                }
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            IPackageManager pm = AppGlobals.getPackageManager();
+            long id = Binder.clearCallingIdentity();
+            try {
+                pm.addPersistentPreferredActivity(filter, activity, UserHandle.getCallingUserId());
+            } catch (RemoteException re) {
+                // Shouldn't happen
+            } finally {
+                restoreCallingIdentity(id);
             }
         }
     }
 
-    public void clearPackagePersistentPreferredActivities(ComponentName admin,
-            String packageName) {
-        int callingUserId = UserHandle.getCallingUserId();
-        Slog.d(LOG_TAG,"called by user " + callingUserId);
+    public void clearPackagePersistentPreferredActivities(ComponentName who, String packageName) {
         synchronized (this) {
-            ActiveAdmin aa = getActiveAdminUncheckedLocked(admin, callingUserId);
-            if (aa == null) {
-                throw new SecurityException("No active admin " + admin);
-            } else {
-                if (isProfileOwner(admin.getPackageName(), callingUserId)
-                        || isDeviceOwner(admin.getPackageName())) {
-                    IPackageManager pm = AppGlobals.getPackageManager();
-                    long id = Binder.clearCallingIdentity();
-                    try{
-                        pm.clearPackagePersistentPreferredActivities(packageName, callingUserId);
-                    } catch (RemoteException re) {
-                        // Shouldn't happen
-                    } finally {
-                        restoreCallingIdentity(id);
-                    }
-                } else {
-                    throw new SecurityException("Admin " + admin +
-                            "is not device owner or profile owner" );
-                }
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            IPackageManager pm = AppGlobals.getPackageManager();
+            long id = Binder.clearCallingIdentity();
+            try {
+                pm.clearPackagePersistentPreferredActivities(packageName, UserHandle.getCallingUserId());
+            } catch (RemoteException re) {
+                // Shouldn't happen
+            } finally {
+                restoreCallingIdentity(id);
             }
         }
     }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c925669..ce205c0 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -50,6 +50,7 @@
 
 import com.android.internal.R;
 import com.android.internal.os.BinderInternal;
+import com.android.internal.os.Zygote;
 import com.android.internal.os.SamplingProfilerIntegration;
 import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.accounts.AccountManagerService;
@@ -76,13 +77,13 @@
 import com.android.server.search.SearchManagerService;
 import com.android.server.statusbar.StatusBarManagerService;
 import com.android.server.storage.DeviceStorageMonitorService;
+import com.android.server.trust.TrustManagerService;
 import com.android.server.twilight.TwilightService;
 import com.android.server.usb.UsbService;
 import com.android.server.wallpaper.WallpaperManagerService;
 import com.android.server.wm.WindowManagerService;
 
 import dalvik.system.VMRuntime;
-import dalvik.system.Zygote;
 
 import java.io.File;
 import java.util.Timer;
@@ -116,6 +117,8 @@
             "com.android.server.usb.UsbService$Lifecycle";
     private static final String WIFI_SERVICE_CLASS =
             "com.android.server.wifi.WifiService";
+    private static final String WIFI_HOTSPOT_SERVICE_CLASS =
+            "com.android.server.wifi.hotspot.WifiHotspotService";
     private static final String WIFI_P2P_SERVICE_CLASS =
             "com.android.server.wifi.p2p.WifiP2pService";
     private static final String HDMI_CEC_SERVICE_CLASS =
@@ -614,6 +617,12 @@
                 }
 
                 try {
+                    mSystemServiceManager.startService(WIFI_HOTSPOT_SERVICE_CLASS);
+                } catch (Throwable e) {
+                    reportWtf("starting Wi-Fi HotspotService", e);
+                }
+
+                try {
                     mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
                 } catch (Throwable e) {
                     reportWtf("starting Wi-Fi Service", e);
@@ -905,6 +914,13 @@
                 } catch (Throwable e) {
                     reportWtf("starting MediaRouterService", e);
                 }
+
+                try {
+                    Slog.i(TAG, "Trust Manager");
+                    mSystemServiceManager.startService(TrustManagerService.class);
+                } catch (Throwable e) {
+                    Slog.e(TAG, "Failure starting TrustManagerService", e);
+                }
             }
         }
 
@@ -913,8 +929,6 @@
         final boolean safeMode = wm.detectSafeMode();
         if (safeMode) {
             mActivityManagerService.enterSafeMode();
-            // Post the safe mode state in the Zygote class
-            Zygote.systemInSafeMode = true;
             // Disable the JIT for the system_server process
             VMRuntime.getRuntime().disableJitCompilation();
         } else {
diff --git a/services/usb/java/com/android/server/usb/UsbDebuggingManager.java b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
index ce953a4..f73d425 100644
--- a/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
@@ -17,8 +17,10 @@
 package com.android.server.usb;
 
 import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
 import android.os.Handler;
@@ -244,15 +246,18 @@
     }
 
     private void showConfirmationDialog(String key, String fingerprints) {
-        Intent dialogIntent = new Intent();
+        Intent intent = new Intent();
 
-        dialogIntent.setClassName("com.android.systemui",
-                "com.android.systemui.usb.UsbDebuggingActivity");
-        dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        dialogIntent.putExtra("key", key);
-        dialogIntent.putExtra("fingerprints", fingerprints);
+        ComponentName componentName = ComponentName.unflattenFromString(
+                Resources.getSystem().getString(
+                        com.android.internal.R.string.config_customAdbPublicKeyActivity));
+        intent.setClassName(componentName.getPackageName(),
+                componentName.getClassName());
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra("key", key);
+        intent.putExtra("fingerprints", fingerprints);
         try {
-            mContext.startActivity(dialogIntent);
+            mContext.startActivity(intent);
         } catch (ActivityNotFoundException e) {
             Slog.e(TAG, "unable to start UsbDebuggingActivity");
         }
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 7ae5460..9ccb809 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -17,6 +17,7 @@
 package com.android.server.usb;
 
 import android.content.Context;
+import android.content.Intent;
 import android.hardware.usb.UsbConfiguration;
 import android.hardware.usb.UsbConstants;
 import android.hardware.usb.UsbDevice;
@@ -25,21 +26,25 @@
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 
+import java.io.File;
 import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Scanner;
 
 /**
  * UsbHostManager manages USB state in host mode.
  */
 public class UsbHostManager {
     private static final String TAG = UsbHostManager.class.getSimpleName();
-    private static final boolean LOG = false;
+    private static final boolean DEBUG_AUDIO = false;
 
     // contains all connected USB devices
     private final HashMap<String, UsbDevice> mDevices = new HashMap<String, UsbDevice>();
@@ -102,6 +107,30 @@
         return false;
     }
 
+    // Broadcasts the arrival/departure of a USB audio interface
+    // card - the ALSA card number of the physical interface
+    // device - the ALSA device number of the physical interface
+    // enabled - if true, we're connecting a device (it's arrived), else disconnecting
+    private void sendDeviceNotification(int card, int device, boolean enabled,
+        boolean hasPlayback, boolean hasCapture, boolean hasMIDI) {
+      // send a sticky broadcast containing current USB state
+      Intent intent = new Intent(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
+      intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+      intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+      intent.putExtra("state", enabled ? 1 : 0);
+      intent.putExtra("card", card);
+      intent.putExtra("device", device);
+      intent.putExtra("hasPlayback", hasPlayback);
+      intent.putExtra("hasCapture", hasCapture);
+      intent.putExtra("hasMIDI", hasMIDI);
+      mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+    }
+
+    static boolean isBuiltInUsbDevice(String deviceName) {
+      // This may be too broad an assumption
+      return deviceName.equals("/dev/bus/usb/001/001");
+    }
+
     /* Called from JNI in monitorUsbHostBus() to report new USB devices
        Returns true if successful, in which case the JNI code will continue adding configurations,
        interfaces and endpoints, and finally call endUsbDeviceAdded after all descriptors
@@ -111,6 +140,59 @@
             int deviceClass, int deviceSubclass, int deviceProtocol,
             String manufacturerName, String productName, String serialNumber) {
 
+      if (DEBUG_AUDIO) {
+          Slog.d(TAG, "usb:UsbHostManager.beginUsbDeviceAdded(" + deviceName + ")");
+          // Audio Class Codes:
+          // Audio: 0x01
+          // Audio Subclass Codes:
+          // undefined: 0x00
+          // audio control: 0x01
+          // audio streaming: 0x02
+          // midi streaming: 0x03
+
+          // some useful debugging info
+          Slog.d(TAG, "usb:UsbHostManager.usbDeviceAdded()");
+          Slog.d(TAG, "usb: nm:" + deviceName +
+              " vnd:" + vendorID +
+              " prd:" + productID +
+              " cls:" + deviceClass +
+              " sub:" + deviceSubclass +
+              " proto:" + deviceProtocol);
+      }
+
+      if (!isBuiltInUsbDevice(deviceName)) {
+          //TODO(pmclean) we will need this when we need to support USB interfaces
+          // beyond card1, device0 but turn them off for now
+          //com.android.alsascan.AlsaCardsParser cardsParser =
+          //    new com.android.alsascan.AlsaCardsParser();
+          //cardsParser.scan();
+          //cardsParser.Log();
+
+          // But we need to parse the device to determine its capabilities.
+          com.android.alsascan.AlsaDevicesParser devicesParser =
+              new com.android.alsascan.AlsaDevicesParser();
+          devicesParser.scan();
+          //devicesParser.Log();
+
+          boolean hasPlaybackDevices = devicesParser.hasPlaybackDevices();
+          boolean hasCaptureDevices = devicesParser.hasCaptureDevices();
+          boolean hasMIDI = devicesParser.hasMIDIDevices();
+
+          if (DEBUG_AUDIO) {
+              Slog.d(TAG, "usb: hasPlayback:" + hasPlaybackDevices
+                      + " hasCapture:" + hasCaptureDevices);
+          }
+
+          //TODO(pmclean)
+          // For now just assume that any USB device that is attached is:
+          // 1. An audio interface and
+          // 2. is card:1 device:0
+          int cardNum = 1;
+          int deviceNum = 0;
+          sendDeviceNotification(cardNum, deviceNum, true,
+                                 hasPlaybackDevices, hasCaptureDevices, hasMIDI);
+        }
+
         if (isBlackListed(deviceName) ||
                 isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) {
             return false;
@@ -176,6 +258,9 @@
 
     /* Called from JNI in monitorUsbHostBus() to finish adding a new device */
     private void endUsbDeviceAdded() {
+        if (DEBUG_AUDIO) {
+            Slog.d(TAG, "usb:UsbHostManager.endUsbDeviceAdded()");
+        }
         if (mNewInterface != null) {
             mNewInterface.setEndpoints(
                     mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()]));
@@ -204,6 +289,13 @@
 
     /* Called from JNI in monitorUsbHostBus to report USB device removal */
     private void usbDeviceRemoved(String deviceName) {
+        if (DEBUG_AUDIO) {
+          Slog.d(TAG, "usb:UsbHostManager.usbDeviceRemoved() nm:" + deviceName);
+        }
+
+        // Same assumptions as the fake-out above
+        sendDeviceNotification(1, 0, false, /*NA*/false, /*NA*/false, /*NA*/false);
+
         synchronized (mLock) {
             UsbDevice device = mDevices.remove(deviceName);
             if (device != null) {
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index 323e0ac..1c75658 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -101,8 +101,93 @@
     /** Unknown error or not specified */
     public static final int ERROR_UNSPECIFIED              = 36;
 
+    /** Smallest valid value for call disconnect codes. */
+    public static final int MINIMUM_VALID_VALUE = NOT_DISCONNECTED;
+    /** Largest valid value for call disconnect codes. */
+    public static final int MAXIMUM_VALID_VALUE = ERROR_UNSPECIFIED;
+
     /** Private constructor to avoid class instantiation. */
     private DisconnectCause() {
         // Do nothing.
     }
+
+    /** Returns descriptive string for the specified disconnect cause. */
+    public static String toString(int cause) {
+        switch (cause) {
+        case NOT_DISCONNECTED:
+            return "NOT_DISCONNECTED";
+        case INCOMING_MISSED:
+            return "INCOMING_MISSED";
+        case NORMAL:
+            return "NORMAL";
+        case LOCAL:
+            return "LOCAL";
+        case BUSY:
+            return "BUSY";
+        case CONGESTION:
+            return "CONGESTION";
+        case INVALID_NUMBER:
+            return "INVALID_NUMBER";
+        case NUMBER_UNREACHABLE:
+            return "NUMBER_UNREACHABLE";
+        case SERVER_UNREACHABLE:
+            return "SERVER_UNREACHABLE";
+        case INVALID_CREDENTIALS:
+            return "INVALID_CREDENTIALS";
+        case OUT_OF_NETWORK:
+            return "OUT_OF_NETWORK";
+        case SERVER_ERROR:
+            return "SERVER_ERROR";
+        case TIMED_OUT:
+            return "TIMED_OUT";
+        case LOST_SIGNAL:
+            return "LOST_SIGNAL";
+        case LIMIT_EXCEEDED:
+            return "LIMIT_EXCEEDED";
+        case INCOMING_REJECTED:
+            return "INCOMING_REJECTED";
+        case POWER_OFF:
+            return "POWER_OFF";
+        case OUT_OF_SERVICE:
+            return "OUT_OF_SERVICE";
+        case ICC_ERROR:
+            return "ICC_ERROR";
+        case CALL_BARRED:
+            return "CALL_BARRED";
+        case FDN_BLOCKED:
+            return "FDN_BLOCKED";
+        case CS_RESTRICTED:
+            return "CS_RESTRICTED";
+        case CS_RESTRICTED_NORMAL:
+            return "CS_RESTRICTED_NORMAL";
+        case CS_RESTRICTED_EMERGENCY:
+            return "CS_RESTRICTED_EMERGENCY";
+        case UNOBTAINABLE_NUMBER:
+            return "UNOBTAINABLE_NUMBER";
+        case CDMA_LOCKED_UNTIL_POWER_CYCLE:
+            return "CDMA_LOCKED_UNTIL_POWER_CYCLE";
+        case CDMA_DROP:
+            return "CDMA_DROP";
+        case CDMA_INTERCEPT:
+            return "CDMA_INTERCEPT";
+        case CDMA_REORDER:
+            return "CDMA_REORDER";
+        case CDMA_SO_REJECT:
+            return "CDMA_SO_REJECT";
+        case CDMA_RETRY_ORDER:
+            return "CDMA_RETRY_ORDER";
+        case CDMA_ACCESS_FAILURE:
+            return "CDMA_ACCESS_FAILURE";
+        case CDMA_PREEMPTED:
+            return "CDMA_PREEMPTED";
+        case CDMA_NOT_EMERGENCY:
+            return "CDMA_NOT_EMERGENCY";
+        case CDMA_ACCESS_BLOCKED:
+            return "CDMA_ACCESS_BLOCKED";
+        case ERROR_UNSPECIFIED:
+            return "ERROR_UNSPECIFIED";
+        default:
+            return "INVALID";
+        }
+    }
 }
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 118cba4..daef37a 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -16,6 +16,7 @@
 
 package android.test.mock;
 
+import android.app.PackageInstallObserver;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -664,4 +665,34 @@
     public VerifierDeviceIdentity getVerifierDeviceIdentity() {
         throw new UnsupportedOperationException();
     }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void installPackage(Uri packageURI, PackageInstallObserver observer,
+            int flags, String installerPackageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void installPackageWithVerification(Uri packageURI,
+            PackageInstallObserver observer, int flags, String installerPackageName,
+            Uri verificationURI, ManifestDigest manifestDigest,
+            ContainerEncryptionParams encryptionParams) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void installPackageWithVerificationAndEncryption(Uri packageURI,
+            PackageInstallObserver observer, int flags, String installerPackageName,
+            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/tests/permission/src/com/android/framework/permission/tests/PmPermissionsTests.java b/tests/permission/src/com/android/framework/permission/tests/PmPermissionsTests.java
index b690c45..93aa555 100644
--- a/tests/permission/src/com/android/framework/permission/tests/PmPermissionsTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/PmPermissionsTests.java
@@ -16,7 +16,7 @@
 
 package com.android.framework.permission.tests;
 
-import junit.framework.TestCase;
+import android.app.PackageInstallObserver;
 import android.content.pm.PackageManager;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -68,10 +68,14 @@
      * This test verifies that PackageManger.installPackage enforces permission
      * android.permission.INSTALL_PACKAGES
      */
+    private class TestInstallObserver extends PackageInstallObserver {
+    }
+
     @SmallTest
     public void testInstallPackage() {
+        TestInstallObserver observer = new TestInstallObserver();
         try {
-            mPm.installPackage(null, null, 0, null);
+            mPm.installPackage(null, observer, 0, null);
             fail("PackageManager.installPackage" +
                     "did not throw SecurityException as expected");
         } catch (SecurityException e) {
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index 1fa9615..cb68340 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -53,6 +53,7 @@
 $(LOCAL_BUILT_MODULE): $(built_core_dep) \
                        $(built_framework_dep) \
                        $(built_ext_dep) \
+                       $(built_ext_data) \
                        $(built_layoutlib_create_jar)
 	$(hide) echo "host layoutlib_create: $@"
 	$(hide) mkdir -p $(dir $@)
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index cfe7525..cc621c4 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -52,9 +52,9 @@
     private final BridgeContext mContext;
     private final boolean mPlatformFile;
 
-    private ResourceValue[] mResourceData;
-    private String[] mNames;
-    private boolean[] mIsFramework;
+    private final ResourceValue[] mResourceData;
+    private final String[] mNames;
+    private final boolean[] mIsFramework;
 
     public BridgeTypedArray(BridgeResources resources, BridgeContext context, int len,
             boolean platformFile) {
@@ -81,8 +81,8 @@
     }
 
     /**
-     * Seals the array after all calls to {@link #bridgeSetValue(int, String, ResourceValue)} have
-     * been done.
+     * Seals the array after all calls to
+     * {@link #bridgeSetValue(int, String, boolean, ResourceValue)} have been done.
      * <p/>This allows to compute the list of non default values, permitting
      * {@link #getIndexCount()} to return the proper value.
      */
@@ -252,7 +252,7 @@
             for (String keyword : keywords) {
                 Integer i = map.get(keyword.trim());
                 if (i != null) {
-                    result |= i.intValue();
+                    result |= i;
                 } else {
                     Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
                             String.format(
@@ -731,7 +731,7 @@
         }
 
         // not a direct id valid reference? resolve it
-        Integer idValue = null;
+        Integer idValue;
 
         if (resValue.isFramework()) {
             idValue = Bridge.getResourceId(resValue.getResourceType(),
@@ -742,7 +742,7 @@
         }
 
         if (idValue != null) {
-            return idValue.intValue();
+            return idValue;
         }
 
         Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_RESOLVE,
@@ -753,6 +753,12 @@
         return defValue;
     }
 
+    @Override
+    public int getThemeAttributeId(int index, int defValue) {
+        // TODO: Get the right Theme Attribute ID to enable caching of the drawables.
+        return defValue;
+    }
+
     /**
      * Retrieve the Drawable for the attribute at <var>index</var>.  This
      * gets the resource ID of the selected attribute, and uses
@@ -854,6 +860,7 @@
      */
     @Override
     public boolean hasValue(int index) {
+        //noinspection SimplifiableIfStatement
         if (index < 0 || index >= mResourceData.length) {
             return false;
         }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java
index 53e1640..a2a8aa9 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java
@@ -18,6 +18,7 @@
 
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
 
 import android.util.SparseArray;
 
@@ -59,10 +60,8 @@
      * number of mappings.
      */
     public SparseWeakArray(int initialCapacity) {
-        initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
-
-        mKeys = new long[initialCapacity];
-        mValues = new WeakReference[initialCapacity];
+        mKeys = ArrayUtils.newUnpaddedLongArray(initialCapacity);
+        mValues = new WeakReference[mKeys.length];
         mSize = 0;
     }
 
@@ -142,18 +141,6 @@
 
         mGarbage = false;
         mSize = o;
-
-        int newSize = ArrayUtils.idealLongArraySize(mSize);
-        if (newSize < mKeys.length) {
-            long[] nkeys = new long[newSize];
-            WeakReference<?>[] nvalues = new WeakReference[newSize];
-
-            System.arraycopy(mKeys, 0, nkeys, 0, newSize);
-            System.arraycopy(mValues, 0, nvalues, 0, newSize);
-
-            mKeys = nkeys;
-            mValues = nvalues;
-        }
     }
 
     /**
@@ -182,28 +169,8 @@
                 i = ~binarySearch(mKeys, 0, mSize, key);
             }
 
-            if (mSize >= mKeys.length) {
-                int n = ArrayUtils.idealLongArraySize(mSize + 1);
-
-                long[] nkeys = new long[n];
-                WeakReference<?>[] nvalues = new WeakReference[n];
-
-                // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
-                System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
-                System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
-                mKeys = nkeys;
-                mValues = nvalues;
-            }
-
-            if (mSize - i != 0) {
-                // Log.e("SparseArray", "move " + (mSize - i));
-                System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
-                System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
-            }
-
-            mKeys[i] = key;
-            mValues[i] = new WeakReference(value);
+            mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
+            mValues = GrowingArrayUtils.insert(mValues, mSize, i, new WeakReference(value));
             mSize++;
         }
     }
@@ -321,24 +288,9 @@
             gc();
         }
 
-        int pos = mSize;
-        if (pos >= mKeys.length) {
-            int n = ArrayUtils.idealLongArraySize(pos + 1);
-
-            long[] nkeys = new long[n];
-            WeakReference<?>[] nvalues = new WeakReference[n];
-
-            // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
-            System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
-            System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
-            mKeys = nkeys;
-            mValues = nvalues;
-        }
-
-        mKeys[pos] = key;
-        mValues[pos] = new WeakReference(value);
-        mSize = pos + 1;
+        mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
+        mValues = GrowingArrayUtils.append(mValues, mSize, new WeakReference(value));
+        mSize++;
     }
 
     private boolean hasReclaimedRefs() {
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
index 9a31705..3e75c9e 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
@@ -632,8 +632,8 @@
             // field instruction
             @Override
             public void visitFieldInsn(int opcode, String owner, String name, String desc) {
-                // name is the field's name.
-                considerName(name);
+                // owner is the class that declares the field.
+                considerName(owner);
                 // desc is the field's descriptor (see Type).
                 considerDesc(desc);
             }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java
index c988c70..2016c0e 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java
@@ -527,7 +527,8 @@
             // field instruction
             @Override
             public void visitFieldInsn(int opcode, String owner, String name, String desc) {
-                // name is the field's name.
+                // owner is the class that declares the field.
+                considerName(owner);
                 // desc is the field's descriptor (see Type).
                 considerDesc(desc);
             }
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
index 7ec0d38..78e2c48 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
@@ -83,6 +83,7 @@
                 "mock_android.dummy.InnerTest$MyStaticInnerClass",
                 "mock_android.dummy.InnerTest$NotStaticInner1",
                 "mock_android.dummy.InnerTest$NotStaticInner2",
+                "mock_android.util.EmptyArray",
                 "mock_android.view.View",
                 "mock_android.view.ViewGroup",
                 "mock_android.view.ViewGroup$LayoutParams",
@@ -217,15 +218,16 @@
         TreeMap<String, ClassReader> in_deps = new TreeMap<String, ClassReader>();
         TreeMap<String, ClassReader> out_deps = new TreeMap<String, ClassReader>();
 
-        ClassReader cr = mAa.findClass("mock_android.widget.TableLayout", zipClasses, keep);
+        ClassReader cr = mAa.findClass("mock_android.widget.LinearLayout", zipClasses, keep);
         DependencyVisitor visitor = mAa.getVisitor(zipClasses, keep, new_keep, in_deps, out_deps);
 
         // get first level dependencies
         cr.accept(visitor, 0 /* flags */);
 
         assertArrayEquals(new String[] {
+                "mock_android.util.EmptyArray",
                 "mock_android.view.ViewGroup",
-                "mock_android.widget.TableLayout$LayoutParams",
+                "mock_android.widget.LinearLayout$LayoutParams",
             },
             out_deps.keySet().toArray());
 
@@ -255,7 +257,7 @@
 
         assertArrayEquals(new String[] { }, out_deps.keySet().toArray());
         assertArrayEquals(new String[] {
-                "mock_android.widget.TableLayout",
+                "mock_android.widget.LinearLayout",
         }, keep.keySet().toArray());
     }
 }
diff --git a/tools/layoutlib/create/tests/data/mock_android.jar b/tools/layoutlib/create/tests/data/mock_android.jar
index 8dd0481..c6ca3c4 100644
--- a/tools/layoutlib/create/tests/data/mock_android.jar
+++ b/tools/layoutlib/create/tests/data/mock_android.jar
Binary files differ
diff --git a/tools/layoutlib/create/tests/mock_data/mock_android/util/EmptyArray.java b/tools/layoutlib/create/tests/mock_data/mock_android/util/EmptyArray.java
new file mode 100644
index 0000000..aaeebf6
--- /dev/null
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/util/EmptyArray.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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 mock_android.util;
+
+import java.lang.JavaClass;
+
+public class EmptyArray {
+
+        public static final Object[] OBJECT = new Object[0];
+}
diff --git a/tools/layoutlib/create/tests/mock_data/mock_android/widget/LinearLayout.java b/tools/layoutlib/create/tests/mock_data/mock_android/widget/LinearLayout.java
index 3870a63..af56c4b 100644
--- a/tools/layoutlib/create/tests/mock_data/mock_android/widget/LinearLayout.java
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/widget/LinearLayout.java
@@ -16,11 +16,13 @@
 
 package mock_android.widget;
 
+import mock_android.util.EmptyArray;
 import mock_android.view.ViewGroup;
 
 public class LinearLayout extends ViewGroup {
 
-    public class LayoutParams extends mock_android.view.ViewGroup.LayoutParams {
+    Object[] mObjects = EmptyArray.OBJECT;
+    public class LayoutParams extends MarginLayoutParams {
 
     }
 
diff --git a/wifi/java/android/net/wifi/BatchedScanSettings.java b/wifi/java/android/net/wifi/BatchedScanSettings.java
index f7ebc17..54801ad 100644
--- a/wifi/java/android/net/wifi/BatchedScanSettings.java
+++ b/wifi/java/android/net/wifi/BatchedScanSettings.java
@@ -34,17 +34,17 @@
     /** Used to indicate no preference for an int value */
     public final static int UNSPECIFIED = Integer.MAX_VALUE;
 
-    // TODO - make MIN/mAX dynamic and gservices adjustable.
+    // TODO - make MIN/mAX as standard for wifi batch capability requirement.
     public final static int MIN_SCANS_PER_BATCH = 2;
-    public final static int MAX_SCANS_PER_BATCH = 255;
+    public final static int MAX_SCANS_PER_BATCH = 20;
     public final static int DEFAULT_SCANS_PER_BATCH = MAX_SCANS_PER_BATCH;
 
     public final static int MIN_AP_PER_SCAN = 2;
-    public final static int MAX_AP_PER_SCAN = 255;
+    public final static int MAX_AP_PER_SCAN = 16;
     public final static int DEFAULT_AP_PER_SCAN = 16;
 
-    public final static int MIN_INTERVAL_SEC = 0;
-    public final static int MAX_INTERVAL_SEC = 3600;
+    public final static int MIN_INTERVAL_SEC = 10;
+    public final static int MAX_INTERVAL_SEC = 500;
     public final static int DEFAULT_INTERVAL_SEC = 30;
 
     public final static int MIN_AP_FOR_DISTANCE = 0;
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 12729d2..d7ecaff 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -40,8 +40,7 @@
      */
     public String capabilities;
     /**
-     * The detected signal level in dBm. At least those are the units used by
-     * the TI driver.
+     * The detected signal level in dBm.
      */
     public int level;
     /**
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 4a6821c..f44cb0a 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -157,9 +157,8 @@
 
     /**
      * Returns the received signal strength indicator of the current 802.11
-     * network.
-     * <p><strong>This is not normalized, but should be!</strong></p>
-     * @return the RSSI, in the range ??? to ???
+     * network, in dBm.
+     * @return the RSSI, in the range -110 to 10
      */
     public int getRssi() {
         return mRssi;
diff --git a/core/java/android/view/DisplayList.java b/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
similarity index 64%
copy from core/java/android/view/DisplayList.java
copy to wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
index ed52803..2b1601b 100644
--- a/core/java/android/view/DisplayList.java
+++ b/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
+/**
+ * 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
+ *     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,
@@ -14,12 +14,15 @@
  * limitations under the License.
  */
 
-package android.view;
+package android.net.wifi.hotspot;
 
-/** TODO: Remove once frameworks/webview is updated
- *  @hide
+/**
+ * Interface that allows controlling and querying Hotspot connectivity.
+ *
+ * {@hide}
  */
-public class DisplayList {
-    /** @hide */
-    public static final int STATUS_DONE = 0x0;
+interface IWifiHotspotManager
+{
+    void test();
 }
+
diff --git a/wifi/java/android/net/wifi/hotspot/WifiHotspotManager.java b/wifi/java/android/net/wifi/hotspot/WifiHotspotManager.java
new file mode 100644
index 0000000..ac15017
--- /dev/null
+++ b/wifi/java/android/net/wifi/hotspot/WifiHotspotManager.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.hotspot;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * TODO: doc
+ */
+public class WifiHotspotManager {
+
+    private static final String TAG = "WifiHotspotManager";
+
+    private Context mContext;
+    IWifiHotspotManager mService;
+
+    public WifiHotspotManager(Context context, IWifiHotspotManager service) {
+        mContext = context;
+        mService = service;
+    }
+
+    public void test() {
+        try{
+            Log.d(TAG, "test()");
+            mService.test();
+        }
+        catch (RemoteException e) {
+            Log.e(TAG, "test() exception");
+            e.printStackTrace();
+        }
+    }
+}