Merge "AudioFlinger: protect input/output stream access"
diff --git a/Android.mk b/Android.mk
index ea8314c..752a5f8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -183,6 +183,7 @@
 	media/java/android/media/IAudioFocusDispatcher.aidl \
 	media/java/android/media/IMediaScannerListener.aidl \
 	media/java/android/media/IMediaScannerService.aidl \
+	media/java/android/media/IRemoteControlClient.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
 	telephony/java/com/android/internal/telephony/ITelephony.aidl \
diff --git a/api/14.txt b/api/14.txt
index 895c44d..3d96c11 100644
--- a/api/14.txt
+++ b/api/14.txt
@@ -20979,45 +20979,17 @@
 
   public class Surface implements android.os.Parcelable {
     method public int describeContents();
-    method public void freeze();
-    method public void hide();
     method public boolean isValid();
     method public android.graphics.Canvas lockCanvas(android.graphics.Rect) throws java.lang.IllegalArgumentException, android.view.Surface.OutOfResourcesException;
     method public void readFromParcel(android.os.Parcel);
-    method public void setAlpha(float);
-    method public void setFlags(int, int);
-    method public void setFreezeTint(int);
-    method public void setLayer(int);
-    method public void setMatrix(float, float, float, float);
-    method public static void setOrientation(int, int);
-    method public void setPosition(int, int);
-    method public void setSize(int, int);
-    method public void setTransparentRegionHint(android.graphics.Region);
-    method public void show();
-    method public void unfreeze();
     method public void unlockCanvas(android.graphics.Canvas);
     method public void unlockCanvasAndPost(android.graphics.Canvas);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
-    field public static final int FX_SURFACE_BLUR = 65536; // 0x10000
-    field public static final int FX_SURFACE_DIM = 131072; // 0x20000
-    field public static final int FX_SURFACE_MASK = 983040; // 0xf0000
-    field public static final int FX_SURFACE_NORMAL = 0; // 0x0
-    field public static final deprecated int GPU = 40; // 0x28
-    field public static final deprecated int HARDWARE = 16; // 0x10
-    field public static final int HIDDEN = 4; // 0x4
-    field public static final int NON_PREMULTIPLIED = 256; // 0x100
-    field public static final deprecated int PUSH_BUFFERS = 512; // 0x200
     field public static final int ROTATION_0 = 0; // 0x0
     field public static final int ROTATION_180 = 2; // 0x2
     field public static final int ROTATION_270 = 3; // 0x3
     field public static final int ROTATION_90 = 1; // 0x1
-    field public static final int SECURE = 128; // 0x80
-    field public static final deprecated int SURACE_FROZEN = 2; // 0x2
-    field public static final int SURFACE_BLUR_FREEZE = 16; // 0x10
-    field public static final int SURFACE_DITHER = 4; // 0x4
-    field public static final int SURFACE_FROZEN = 2; // 0x2
-    field public static final int SURFACE_HIDDEN = 1; // 0x1
   }
 
   public static class Surface.OutOfResourcesException extends java.lang.Exception {
diff --git a/api/current.txt b/api/current.txt
index 6cef3a7..5a599ce 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -15,6 +15,7 @@
     field public static final java.lang.String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER";
     field public static final java.lang.String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
     field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
+    field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
     field public static final java.lang.String AUTHENTICATE_ACCOUNTS = "android.permission.AUTHENTICATE_ACCOUNTS";
     field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
     field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -83,7 +84,6 @@
     field public static final java.lang.String READ_SMS = "android.permission.READ_SMS";
     field public static final java.lang.String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS";
     field public static final java.lang.String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS";
-    field public static final java.lang.String READ_WRITE_OWN_VOICEMAIL = "com.android.voicemail.permission.READ_WRITE_OWN_VOICEMAIL";
     field public static final java.lang.String REBOOT = "android.permission.REBOOT";
     field public static final java.lang.String RECEIVE_BOOT_COMPLETED = "android.permission.RECEIVE_BOOT_COMPLETED";
     field public static final java.lang.String RECEIVE_MMS = "android.permission.RECEIVE_MMS";
@@ -911,6 +911,8 @@
     field public static final int stretchMode = 16843030; // 0x1010116
     field public static final int subtitle = 16843473; // 0x10102d1
     field public static final int subtitleTextStyle = 16843513; // 0x10102f9
+    field public static final int subtypeExtraValue = 16843684; // 0x10103a4
+    field public static final int subtypeLocale = 16843683; // 0x10103a3
     field public static final int suggestActionMsg = 16843228; // 0x10101dc
     field public static final int suggestActionMsgColumn = 16843229; // 0x10101dd
     field public static final int suggestionsEnabled = 16843632; // 0x1010370
@@ -1031,6 +1033,7 @@
     field public static final int translationY = 16843555; // 0x1010323
     field public static final int type = 16843169; // 0x10101a1
     field public static final int typeface = 16842902; // 0x1010096
+    field public static final int uiOptions = 16843682; // 0x10103a2
     field public static final int uncertainGestureColor = 16843382; // 0x1010276
     field public static final int unfocusedMonthDateColor = 16843588; // 0x1010344
     field public static final int unselectedAlpha = 16843278; // 0x101020e
@@ -1497,6 +1500,12 @@
     field public static final int Animation_InputMethod = 16973910; // 0x1030056
     field public static final int Animation_Toast = 16973828; // 0x1030004
     field public static final int Animation_Translucent = 16973827; // 0x1030003
+    field public static final int DeviceDefault_ButtonBar = 16974287; // 0x10301cf
+    field public static final int DeviceDefault_ButtonBar_AlertDialog = 16974288; // 0x10301d0
+    field public static final int DeviceDefault_Light_ButtonBar = 16974290; // 0x10301d2
+    field public static final int DeviceDefault_Light_ButtonBar_AlertDialog = 16974291; // 0x10301d3
+    field public static final int DeviceDefault_Light_SegmentedButton = 16974292; // 0x10301d4
+    field public static final int DeviceDefault_SegmentedButton = 16974289; // 0x10301d1
     field public static final int Holo_ButtonBar = 16974053; // 0x10300e5
     field public static final int Holo_ButtonBar_AlertDialog = 16974055; // 0x10300e7
     field public static final int Holo_Light_ButtonBar = 16974054; // 0x10300e6
@@ -1511,6 +1520,40 @@
     field public static final int MediaButton_Previous = 16973880; // 0x1030038
     field public static final int MediaButton_Rew = 16973884; // 0x103003c
     field public static final int TextAppearance = 16973886; // 0x103003e
+    field public static final int TextAppearance_DeviceDefault = 16974253; // 0x10301ad
+    field public static final int TextAppearance_DeviceDefault_DialogWindowTitle = 16974264; // 0x10301b8
+    field public static final int TextAppearance_DeviceDefault_Inverse = 16974254; // 0x10301ae
+    field public static final int TextAppearance_DeviceDefault_Large = 16974255; // 0x10301af
+    field public static final int TextAppearance_DeviceDefault_Large_Inverse = 16974256; // 0x10301b0
+    field public static final int TextAppearance_DeviceDefault_Medium = 16974257; // 0x10301b1
+    field public static final int TextAppearance_DeviceDefault_Medium_Inverse = 16974258; // 0x10301b2
+    field public static final int TextAppearance_DeviceDefault_SearchResult_Subtitle = 16974262; // 0x10301b6
+    field public static final int TextAppearance_DeviceDefault_SearchResult_Title = 16974261; // 0x10301b5
+    field public static final int TextAppearance_DeviceDefault_Small = 16974259; // 0x10301b3
+    field public static final int TextAppearance_DeviceDefault_Small_Inverse = 16974260; // 0x10301b4
+    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 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 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 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 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
+    field public static final int TextAppearance_DeviceDefault_Widget_EditText = 16974274; // 0x10301c2
+    field public static final int TextAppearance_DeviceDefault_Widget_IconMenu_Item = 16974267; // 0x10301bb
+    field public static final int TextAppearance_DeviceDefault_Widget_PopupMenu = 16974275; // 0x10301c3
+    field public static final int TextAppearance_DeviceDefault_Widget_PopupMenu_Large = 16974276; // 0x10301c4
+    field public static final int TextAppearance_DeviceDefault_Widget_PopupMenu_Small = 16974277; // 0x10301c5
+    field public static final int TextAppearance_DeviceDefault_Widget_TabWidget = 16974268; // 0x10301bc
+    field public static final int TextAppearance_DeviceDefault_Widget_TextView = 16974269; // 0x10301bd
+    field public static final int TextAppearance_DeviceDefault_Widget_TextView_PopupMenu = 16974270; // 0x10301be
+    field public static final int TextAppearance_DeviceDefault_Widget_TextView_SpinnerItem = 16974273; // 0x10301c1
+    field public static final int TextAppearance_DeviceDefault_WindowTitle = 16974263; // 0x10301b7
     field public static final int TextAppearance_DialogWindowTitle = 16973889; // 0x1030041
     field public static final int TextAppearance_Holo = 16974075; // 0x10300fb
     field public static final int TextAppearance_Holo_DialogWindowTitle = 16974103; // 0x1030117
@@ -1524,15 +1567,15 @@
     field public static final int TextAppearance_Holo_Small = 16974081; // 0x1030101
     field public static final int TextAppearance_Holo_Small_Inverse = 16974082; // 0x1030102
     field public static final int TextAppearance_Holo_Widget = 16974085; // 0x1030105
-    field public static final int TextAppearance_Holo_Widget_ActionBar_Menu = 16974113; // 0x1030121
+    field public static final int TextAppearance_Holo_Widget_ActionBar_Menu = 16974112; // 0x1030120
     field public static final int TextAppearance_Holo_Widget_ActionBar_Subtitle = 16974099; // 0x1030113
-    field public static final int TextAppearance_Holo_Widget_ActionBar_Subtitle_Inverse = 16974110; // 0x103011e
+    field public static final int TextAppearance_Holo_Widget_ActionBar_Subtitle_Inverse = 16974109; // 0x103011d
     field public static final int TextAppearance_Holo_Widget_ActionBar_Title = 16974098; // 0x1030112
-    field public static final int TextAppearance_Holo_Widget_ActionBar_Title_Inverse = 16974109; // 0x103011d
+    field public static final int TextAppearance_Holo_Widget_ActionBar_Title_Inverse = 16974108; // 0x103011c
     field public static final int TextAppearance_Holo_Widget_ActionMode_Subtitle = 16974101; // 0x1030115
-    field public static final int TextAppearance_Holo_Widget_ActionMode_Subtitle_Inverse = 16974112; // 0x1030120
+    field public static final int TextAppearance_Holo_Widget_ActionMode_Subtitle_Inverse = 16974111; // 0x103011f
     field public static final int TextAppearance_Holo_Widget_ActionMode_Title = 16974100; // 0x1030114
-    field public static final int TextAppearance_Holo_Widget_ActionMode_Title_Inverse = 16974111; // 0x103011f
+    field public static final int TextAppearance_Holo_Widget_ActionMode_Title_Inverse = 16974110; // 0x103011e
     field public static final int TextAppearance_Holo_Widget_Button = 16974086; // 0x1030106
     field public static final int TextAppearance_Holo_Widget_DropDownHint = 16974091; // 0x103010b
     field public static final int TextAppearance_Holo_Widget_DropDownItem = 16974092; // 0x103010c
@@ -1576,6 +1619,30 @@
     field public static final int Theme_Black = 16973832; // 0x1030008
     field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
     field public static final int Theme_Black_NoTitleBar_Fullscreen = 16973834; // 0x103000a
+    field public static final int Theme_DeviceDefault = 16974120; // 0x1030128
+    field public static final int Theme_DeviceDefault_Dialog = 16974126; // 0x103012e
+    field public static final int Theme_DeviceDefault_DialogWhenLarge = 16974134; // 0x1030136
+    field public static final int Theme_DeviceDefault_DialogWhenLarge_NoActionBar = 16974135; // 0x1030137
+    field public static final int Theme_DeviceDefault_Dialog_MinWidth = 16974127; // 0x103012f
+    field public static final int Theme_DeviceDefault_Dialog_NoActionBar = 16974128; // 0x1030130
+    field public static final int Theme_DeviceDefault_Dialog_NoActionBar_MinWidth = 16974129; // 0x1030131
+    field public static final int Theme_DeviceDefault_InputMethod = 16974142; // 0x103013e
+    field public static final int Theme_DeviceDefault_Light = 16974123; // 0x103012b
+    field public static final int Theme_DeviceDefault_Light_DarkActionBar = 16974143; // 0x103013f
+    field public static final int Theme_DeviceDefault_Light_Dialog = 16974130; // 0x1030132
+    field public static final int Theme_DeviceDefault_Light_DialogWhenLarge = 16974136; // 0x1030138
+    field public static final int Theme_DeviceDefault_Light_DialogWhenLarge_NoActionBar = 16974137; // 0x1030139
+    field public static final int Theme_DeviceDefault_Light_Dialog_MinWidth = 16974131; // 0x1030133
+    field public static final int Theme_DeviceDefault_Light_Dialog_NoActionBar = 16974132; // 0x1030134
+    field public static final int Theme_DeviceDefault_Light_Dialog_NoActionBar_MinWidth = 16974133; // 0x1030135
+    field public static final int Theme_DeviceDefault_Light_NoActionBar = 16974124; // 0x103012c
+    field public static final int Theme_DeviceDefault_Light_NoActionBar_Fullscreen = 16974125; // 0x103012d
+    field public static final int Theme_DeviceDefault_Light_Panel = 16974139; // 0x103013b
+    field public static final int Theme_DeviceDefault_NoActionBar = 16974121; // 0x1030129
+    field public static final int Theme_DeviceDefault_NoActionBar_Fullscreen = 16974122; // 0x103012a
+    field public static final int Theme_DeviceDefault_Panel = 16974138; // 0x103013a
+    field public static final int Theme_DeviceDefault_Wallpaper = 16974140; // 0x103013c
+    field public static final int Theme_DeviceDefault_Wallpaper_NoTitleBar = 16974141; // 0x103013d
     field public static final int Theme_Dialog = 16973835; // 0x103000b
     field public static final int Theme_Holo = 16973931; // 0x103006b
     field public static final int Theme_Holo_Dialog = 16973935; // 0x103006f
@@ -1586,6 +1653,7 @@
     field public static final int Theme_Holo_Dialog_NoActionBar_MinWidth = 16973938; // 0x1030072
     field public static final int Theme_Holo_InputMethod = 16973951; // 0x103007f
     field public static final int Theme_Holo_Light = 16973934; // 0x103006e
+    field public static final int Theme_Holo_Light_DarkActionBar = 16974105; // 0x1030119
     field public static final int Theme_Holo_Light_Dialog = 16973939; // 0x1030073
     field public static final int Theme_Holo_Light_DialogWhenLarge = 16973945; // 0x1030079
     field public static final int Theme_Holo_Light_DialogWhenLarge_NoActionBar = 16973946; // 0x103007a
@@ -1595,17 +1663,9 @@
     field public static final int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0
     field public static final int Theme_Holo_Light_NoActionBar_Fullscreen = 16974065; // 0x10300f1
     field public static final int Theme_Holo_Light_Panel = 16973948; // 0x103007c
-    field public static final int Theme_Holo_Light_SolidActionBar = 16974122; // 0x103012a
-    field public static final int Theme_Holo_Light_SolidActionBar_Inverse = 16974123; // 0x103012b
-    field public static final int Theme_Holo_Light_SolidActionBar_Inverse_SplitActionBarWhenNarrow = 16974126; // 0x103012e
-    field public static final int Theme_Holo_Light_SolidActionBar_SplitActionBarWhenNarrow = 16974125; // 0x103012d
-    field public static final int Theme_Holo_Light_SplitActionBarWhenNarrow = 16974106; // 0x103011a
     field public static final int Theme_Holo_NoActionBar = 16973932; // 0x103006c
     field public static final int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d
     field public static final int Theme_Holo_Panel = 16973947; // 0x103007b
-    field public static final int Theme_Holo_SolidActionBar = 16974121; // 0x1030129
-    field public static final int Theme_Holo_SolidActionBar_SplitActionBarWhenNarrow = 16974124; // 0x103012c
-    field public static final int Theme_Holo_SplitActionBarWhenNarrow = 16974105; // 0x1030119
     field public static final int Theme_Holo_Wallpaper = 16973949; // 0x103007d
     field public static final int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e
     field public static final int Theme_InputMethod = 16973908; // 0x1030054
@@ -1647,6 +1707,115 @@
     field public static final int Widget_CompoundButton_RadioButton = 16973850; // 0x103001a
     field public static final int Widget_CompoundButton_Star = 16973851; // 0x103001b
     field public static final int Widget_DatePicker = 16974062; // 0x10300ee
+    field public static final int Widget_DeviceDefault = 16974144; // 0x1030140
+    field public static final int Widget_DeviceDefault_ActionBar = 16974187; // 0x103016b
+    field public static final int Widget_DeviceDefault_ActionBar_Solid = 16974195; // 0x1030173
+    field public static final int Widget_DeviceDefault_ActionBar_TabBar = 16974194; // 0x1030172
+    field public static final int Widget_DeviceDefault_ActionBar_TabText = 16974193; // 0x1030171
+    field public static final int Widget_DeviceDefault_ActionBar_TabView = 16974192; // 0x1030170
+    field public static final int Widget_DeviceDefault_ActionButton = 16974182; // 0x1030166
+    field public static final int Widget_DeviceDefault_ActionButton_CloseMode = 16974186; // 0x103016a
+    field public static final int Widget_DeviceDefault_ActionButton_Overflow = 16974183; // 0x1030167
+    field public static final int Widget_DeviceDefault_ActionButton_TextButton = 16974184; // 0x1030168
+    field public static final int Widget_DeviceDefault_ActionMode = 16974185; // 0x1030169
+    field public static final int Widget_DeviceDefault_AutoCompleteTextView = 16974151; // 0x1030147
+    field public static final int Widget_DeviceDefault_Button = 16974145; // 0x1030141
+    field public static final int Widget_DeviceDefault_Button_Borderless = 16974188; // 0x103016c
+    field public static final int Widget_DeviceDefault_Button_Borderless_Small = 16974149; // 0x1030145
+    field public static final int Widget_DeviceDefault_Button_Inset = 16974147; // 0x1030143
+    field public static final int Widget_DeviceDefault_Button_Small = 16974146; // 0x1030142
+    field public static final int Widget_DeviceDefault_Button_Toggle = 16974148; // 0x1030144
+    field public static final int Widget_DeviceDefault_CalendarView = 16974190; // 0x103016e
+    field public static final int Widget_DeviceDefault_CompoundButton_CheckBox = 16974152; // 0x1030148
+    field public static final int Widget_DeviceDefault_CompoundButton_RadioButton = 16974169; // 0x1030159
+    field public static final int Widget_DeviceDefault_CompoundButton_Star = 16974173; // 0x103015d
+    field public static final int Widget_DeviceDefault_DatePicker = 16974191; // 0x103016f
+    field public static final int Widget_DeviceDefault_DropDownItem = 16974177; // 0x1030161
+    field public static final int Widget_DeviceDefault_DropDownItem_Spinner = 16974178; // 0x1030162
+    field public static final int Widget_DeviceDefault_EditText = 16974154; // 0x103014a
+    field public static final int Widget_DeviceDefault_ExpandableListView = 16974155; // 0x103014b
+    field public static final int Widget_DeviceDefault_GridView = 16974156; // 0x103014c
+    field public static final int Widget_DeviceDefault_HorizontalScrollView = 16974171; // 0x103015b
+    field public static final int Widget_DeviceDefault_ImageButton = 16974157; // 0x103014d
+    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 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 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 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 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 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
+    field public static final int Widget_DeviceDefault_Light_Button_Inset = 16974199; // 0x1030177
+    field public static final int Widget_DeviceDefault_Light_Button_Small = 16974198; // 0x1030176
+    field public static final int Widget_DeviceDefault_Light_Button_Toggle = 16974200; // 0x1030178
+    field public static final int Widget_DeviceDefault_Light_CalendarView = 16974238; // 0x103019e
+    field public static final int Widget_DeviceDefault_Light_CompoundButton_CheckBox = 16974204; // 0x103017c
+    field public static final int Widget_DeviceDefault_Light_CompoundButton_RadioButton = 16974224; // 0x1030190
+    field public static final int Widget_DeviceDefault_Light_CompoundButton_Star = 16974228; // 0x1030194
+    field public static final int Widget_DeviceDefault_Light_DropDownItem = 16974232; // 0x1030198
+    field public static final int Widget_DeviceDefault_Light_DropDownItem_Spinner = 16974233; // 0x1030199
+    field public static final int Widget_DeviceDefault_Light_EditText = 16974206; // 0x103017e
+    field public static final int Widget_DeviceDefault_Light_ExpandableListView = 16974207; // 0x103017f
+    field public static final int Widget_DeviceDefault_Light_GridView = 16974208; // 0x1030180
+    field public static final int Widget_DeviceDefault_Light_HorizontalScrollView = 16974226; // 0x1030192
+    field public static final int Widget_DeviceDefault_Light_ImageButton = 16974209; // 0x1030181
+    field public static final int Widget_DeviceDefault_Light_ListPopupWindow = 16974235; // 0x103019b
+    field public static final int Widget_DeviceDefault_Light_ListView = 16974210; // 0x1030182
+    field public static final int Widget_DeviceDefault_Light_ListView_DropDown = 16974205; // 0x103017d
+    field public static final int Widget_DeviceDefault_Light_PopupMenu = 16974236; // 0x103019c
+    field public static final int Widget_DeviceDefault_Light_PopupWindow = 16974211; // 0x1030183
+    field public static final int Widget_DeviceDefault_Light_ProgressBar = 16974212; // 0x1030184
+    field public static final int Widget_DeviceDefault_Light_ProgressBar_Horizontal = 16974213; // 0x1030185
+    field public static final int Widget_DeviceDefault_Light_ProgressBar_Inverse = 16974217; // 0x1030189
+    field public static final int Widget_DeviceDefault_Light_ProgressBar_Large = 16974216; // 0x1030188
+    field public static final int Widget_DeviceDefault_Light_ProgressBar_Large_Inverse = 16974219; // 0x103018b
+    field public static final int Widget_DeviceDefault_Light_ProgressBar_Small = 16974214; // 0x1030186
+    field public static final int Widget_DeviceDefault_Light_ProgressBar_Small_Inverse = 16974218; // 0x103018a
+    field public static final int Widget_DeviceDefault_Light_ProgressBar_Small_Title = 16974215; // 0x1030187
+    field public static final int Widget_DeviceDefault_Light_RatingBar = 16974221; // 0x103018d
+    field public static final int Widget_DeviceDefault_Light_RatingBar_Indicator = 16974222; // 0x103018e
+    field public static final int Widget_DeviceDefault_Light_RatingBar_Small = 16974223; // 0x103018f
+    field public static final int Widget_DeviceDefault_Light_ScrollView = 16974225; // 0x1030191
+    field public static final int Widget_DeviceDefault_Light_SeekBar = 16974220; // 0x103018c
+    field public static final int Widget_DeviceDefault_Light_Spinner = 16974227; // 0x1030193
+    field public static final int Widget_DeviceDefault_Light_Tab = 16974237; // 0x103019d
+    field public static final int Widget_DeviceDefault_Light_TabWidget = 16974229; // 0x1030195
+    field public static final int Widget_DeviceDefault_Light_TextView = 16974202; // 0x103017a
+    field public static final int Widget_DeviceDefault_Light_TextView_SpinnerItem = 16974234; // 0x103019a
+    field public static final int Widget_DeviceDefault_Light_WebTextView = 16974230; // 0x1030196
+    field public static final int Widget_DeviceDefault_Light_WebView = 16974231; // 0x1030197
+    field public static final int Widget_DeviceDefault_ListPopupWindow = 16974180; // 0x1030164
+    field public static final int Widget_DeviceDefault_ListView = 16974158; // 0x103014e
+    field public static final int Widget_DeviceDefault_ListView_DropDown = 16974153; // 0x1030149
+    field public static final int Widget_DeviceDefault_PopupMenu = 16974181; // 0x1030165
+    field public static final int Widget_DeviceDefault_PopupWindow = 16974159; // 0x103014f
+    field public static final int Widget_DeviceDefault_ProgressBar = 16974160; // 0x1030150
+    field public static final int Widget_DeviceDefault_ProgressBar_Horizontal = 16974161; // 0x1030151
+    field public static final int Widget_DeviceDefault_ProgressBar_Large = 16974164; // 0x1030154
+    field public static final int Widget_DeviceDefault_ProgressBar_Small = 16974162; // 0x1030152
+    field public static final int Widget_DeviceDefault_ProgressBar_Small_Title = 16974163; // 0x1030153
+    field public static final int Widget_DeviceDefault_RatingBar = 16974166; // 0x1030156
+    field public static final int Widget_DeviceDefault_RatingBar_Indicator = 16974167; // 0x1030157
+    field public static final int Widget_DeviceDefault_RatingBar_Small = 16974168; // 0x1030158
+    field public static final int Widget_DeviceDefault_ScrollView = 16974170; // 0x103015a
+    field public static final int Widget_DeviceDefault_SeekBar = 16974165; // 0x1030155
+    field public static final int Widget_DeviceDefault_Spinner = 16974172; // 0x103015c
+    field public static final int Widget_DeviceDefault_Tab = 16974189; // 0x103016d
+    field public static final int Widget_DeviceDefault_TabWidget = 16974174; // 0x103015e
+    field public static final int Widget_DeviceDefault_TextView = 16974150; // 0x1030146
+    field public static final int Widget_DeviceDefault_TextView_SpinnerItem = 16974179; // 0x1030163
+    field public static final int Widget_DeviceDefault_WebTextView = 16974175; // 0x103015f
+    field public static final int Widget_DeviceDefault_WebView = 16974176; // 0x1030160
     field public static final int Widget_DropDownItem = 16973867; // 0x103002b
     field public static final int Widget_DropDownItem_Spinner = 16973868; // 0x103002c
     field public static final int Widget_EditText = 16973859; // 0x1030023
@@ -1656,7 +1825,7 @@
     field public static final int Widget_GridView = 16973874; // 0x1030032
     field public static final int Widget_Holo = 16973962; // 0x103008a
     field public static final int Widget_Holo_ActionBar = 16974004; // 0x10300b4
-    field public static final int Widget_Holo_ActionBar_Solid = 16974114; // 0x1030122
+    field public static final int Widget_Holo_ActionBar_Solid = 16974113; // 0x1030121
     field public static final int Widget_Holo_ActionBar_TabBar = 16974071; // 0x10300f7
     field public static final int Widget_Holo_ActionBar_TabText = 16974070; // 0x10300f6
     field public static final int Widget_Holo_ActionBar_TabView = 16974069; // 0x10300f5
@@ -1668,7 +1837,7 @@
     field public static final int Widget_Holo_AutoCompleteTextView = 16973968; // 0x1030090
     field public static final int Widget_Holo_Button = 16973963; // 0x103008b
     field public static final int Widget_Holo_Button_Borderless = 16974050; // 0x10300e2
-    field public static final int Widget_Holo_Button_Borderless_Small = 16974107; // 0x103011b
+    field public static final int Widget_Holo_Button_Borderless_Small = 16974106; // 0x103011a
     field public static final int Widget_Holo_Button_Inset = 16973965; // 0x103008d
     field public static final int Widget_Holo_Button_Small = 16973964; // 0x103008c
     field public static final int Widget_Holo_Button_Toggle = 16973966; // 0x103008e
@@ -1686,22 +1855,22 @@
     field public static final int Widget_Holo_ImageButton = 16973974; // 0x1030096
     field public static final int Widget_Holo_Light = 16974005; // 0x10300b5
     field public static final int Widget_Holo_Light_ActionBar = 16974049; // 0x10300e1
-    field public static final int Widget_Holo_Light_ActionBar_Solid = 16974115; // 0x1030123
-    field public static final int Widget_Holo_Light_ActionBar_Solid_Inverse = 16974116; // 0x1030124
+    field public static final int Widget_Holo_Light_ActionBar_Solid = 16974114; // 0x1030122
+    field public static final int Widget_Holo_Light_ActionBar_Solid_Inverse = 16974115; // 0x1030123
     field public static final int Widget_Holo_Light_ActionBar_TabBar = 16974074; // 0x10300fa
-    field public static final int Widget_Holo_Light_ActionBar_TabBar_Inverse = 16974117; // 0x1030125
+    field public static final int Widget_Holo_Light_ActionBar_TabBar_Inverse = 16974116; // 0x1030124
     field public static final int Widget_Holo_Light_ActionBar_TabText = 16974073; // 0x10300f9
-    field public static final int Widget_Holo_Light_ActionBar_TabText_Inverse = 16974119; // 0x1030127
+    field public static final int Widget_Holo_Light_ActionBar_TabText_Inverse = 16974118; // 0x1030126
     field public static final int Widget_Holo_Light_ActionBar_TabView = 16974072; // 0x10300f8
-    field public static final int Widget_Holo_Light_ActionBar_TabView_Inverse = 16974118; // 0x1030126
+    field public static final int Widget_Holo_Light_ActionBar_TabView_Inverse = 16974117; // 0x1030125
     field public static final int Widget_Holo_Light_ActionButton = 16974045; // 0x10300dd
     field public static final int Widget_Holo_Light_ActionButton_CloseMode = 16974048; // 0x10300e0
     field public static final int Widget_Holo_Light_ActionButton_Overflow = 16974046; // 0x10300de
     field public static final int Widget_Holo_Light_ActionMode = 16974047; // 0x10300df
-    field public static final int Widget_Holo_Light_ActionMode_Inverse = 16974120; // 0x1030128
+    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_Small = 16974108; // 0x103011c
+    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
     field public static final int Widget_Holo_Light_Button_Toggle = 16974009; // 0x10300b9
@@ -5637,6 +5806,7 @@
     field public static final int SCREEN_ORIENTATION_SENSOR_PORTRAIT = 7; // 0x7
     field public static final int SCREEN_ORIENTATION_UNSPECIFIED = -1; // 0xffffffff
     field public static final int SCREEN_ORIENTATION_USER = 2; // 0x2
+    field public static final int UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW = 1; // 0x1
     field public int configChanges;
     field public int flags;
     field public int launchMode;
@@ -5646,6 +5816,7 @@
     field public java.lang.String targetActivity;
     field public java.lang.String taskAffinity;
     field public int theme;
+    field public int uiOptions;
   }
 
   public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
@@ -5696,6 +5867,7 @@
     field public int targetSdkVersion;
     field public java.lang.String taskAffinity;
     field public int theme;
+    field public int uiOptions;
     field public int uid;
   }
 
@@ -8456,6 +8628,7 @@
     ctor public SurfaceTexture(int, boolean);
     method public long getTimestamp();
     method public void getTransformMatrix(float[]);
+    method public void release();
     method public void setOnFrameAvailableListener(android.graphics.SurfaceTexture.OnFrameAvailableListener);
     method public void updateTexImage();
   }
@@ -11118,6 +11291,7 @@
 
   public class ConnectivityManager {
     method public android.net.NetworkInfo getActiveNetworkInfo();
+    method public android.net.NetworkQuotaInfo getActiveNetworkQuotaInfo();
     method public android.net.NetworkInfo[] getAllNetworkInfo();
     method public boolean getBackgroundDataSetting();
     method public android.net.NetworkInfo getNetworkInfo(int);
@@ -11132,7 +11306,7 @@
     field public static final int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
     field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
     field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover";
-    field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
+    field public static final deprecated java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
     field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
     field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
     field public static final java.lang.String EXTRA_REASON = "reason";
@@ -11277,6 +11451,16 @@
     enum_constant public static final android.net.NetworkInfo.State UNKNOWN;
   }
 
+  public class NetworkQuotaInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getEstimatedBytes();
+    method public long getHardLimitBytes();
+    method public long getSoftLimitBytes();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final long NO_LIMIT = -1L; // 0xffffffffffffffffL
+  }
+
   public class ParseException extends java.lang.RuntimeException {
     field public java.lang.String response;
   }
@@ -13913,6 +14097,7 @@
     method public static long getNativeHeapAllocatedSize();
     method public static long getNativeHeapFreeSize();
     method public static long getNativeHeapSize();
+    method public static long getPss();
     method public static int getThreadAllocCount();
     method public static int getThreadAllocSize();
     method public static deprecated int getThreadExternalAllocCount();
@@ -18003,13 +18188,21 @@
 
   public abstract class SpellCheckerService extends android.app.Service {
     ctor public SpellCheckerService();
-    method public void cancel();
-    method public abstract android.view.textservice.SuggestionsInfo getSuggestions(android.view.textservice.TextInfo, int, java.lang.String);
-    method public android.view.textservice.SuggestionsInfo[] getSuggestionsMultiple(android.view.textservice.TextInfo[], java.lang.String, int, boolean);
+    method public abstract android.service.textservice.SpellCheckerService.Session createSession();
     method public final android.os.IBinder onBind(android.content.Intent);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.textservice.SpellCheckerService";
   }
 
+  public abstract class SpellCheckerService.Session {
+    ctor public SpellCheckerService.Session();
+    method public android.os.Bundle getBundle();
+    method public java.lang.String getLocale();
+    method public void onCancel();
+    method public abstract void onCreate();
+    method public abstract android.view.textservice.SuggestionsInfo onGetSuggestions(android.view.textservice.TextInfo, int);
+    method public android.view.textservice.SuggestionsInfo[] onGetSuggestionsMultiple(android.view.textservice.TextInfo[], int, boolean);
+  }
+
 }
 
 package android.service.wallpaper {
@@ -22070,45 +22263,18 @@
 
   public class Surface implements android.os.Parcelable {
     method public int describeContents();
-    method public void freeze();
-    method public void hide();
     method public boolean isValid();
     method public android.graphics.Canvas lockCanvas(android.graphics.Rect) throws java.lang.IllegalArgumentException, android.view.Surface.OutOfResourcesException;
     method public void readFromParcel(android.os.Parcel);
-    method public void setAlpha(float);
-    method public void setFlags(int, int);
-    method public void setFreezeTint(int);
-    method public void setLayer(int);
-    method public void setMatrix(float, float, float, float);
-    method public static void setOrientation(int, int);
-    method public void setPosition(int, int);
-    method public void setSize(int, int);
-    method public void setTransparentRegionHint(android.graphics.Region);
-    method public void show();
-    method public void unfreeze();
+    method public void release();
     method public void unlockCanvas(android.graphics.Canvas);
     method public void unlockCanvasAndPost(android.graphics.Canvas);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
-    field public static final int FX_SURFACE_BLUR = 65536; // 0x10000
-    field public static final int FX_SURFACE_DIM = 131072; // 0x20000
-    field public static final int FX_SURFACE_MASK = 983040; // 0xf0000
-    field public static final int FX_SURFACE_NORMAL = 0; // 0x0
-    field public static final deprecated int GPU = 40; // 0x28
-    field public static final deprecated int HARDWARE = 16; // 0x10
-    field public static final int HIDDEN = 4; // 0x4
-    field public static final int NON_PREMULTIPLIED = 256; // 0x100
-    field public static final deprecated int PUSH_BUFFERS = 512; // 0x200
     field public static final int ROTATION_0 = 0; // 0x0
     field public static final int ROTATION_180 = 2; // 0x2
     field public static final int ROTATION_270 = 3; // 0x3
     field public static final int ROTATION_90 = 1; // 0x1
-    field public static final int SECURE = 128; // 0x80
-    field public static final deprecated int SURACE_FROZEN = 2; // 0x2
-    field public static final int SURFACE_BLUR_FREEZE = 16; // 0x10
-    field public static final int SURFACE_DITHER = 4; // 0x4
-    field public static final int SURFACE_FROZEN = 2; // 0x2
-    field public static final int SURFACE_HIDDEN = 1; // 0x1
   }
 
   public static class Surface.OutOfResourcesException extends java.lang.Exception {
@@ -23162,6 +23328,7 @@
     method public abstract void setTitle(java.lang.CharSequence);
     method public abstract void setTitleColor(int);
     method public void setType(int);
+    method public void setUiOptions(int);
     method public abstract void setVolumeControlStream(int);
     method public void setWindowAnimations(int);
     method public void setWindowManager(android.view.WindowManager, android.os.IBinder, java.lang.String);
@@ -24103,6 +24270,9 @@
     method public android.content.ComponentName getComponent();
     method public java.lang.String getId();
     method public java.lang.String getPackageName();
+    method public java.lang.String getSettingsActivity();
+    method public android.view.textservice.SpellCheckerSubtype getSubtypeAt(int);
+    method public int getSubtypeCount();
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
     method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
     method public void writeToParcel(android.os.Parcel, int);
@@ -24122,6 +24292,16 @@
     method public abstract void onGetSuggestions(android.view.textservice.SuggestionsInfo[]);
   }
 
+  public final class SpellCheckerSubtype implements android.os.Parcelable {
+    ctor public SpellCheckerSubtype(int, java.lang.String, java.lang.String);
+    method public int describeContents();
+    method public java.lang.String getExtraValue();
+    method public java.lang.String getLocale();
+    method public int getNameResId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
   public final class SuggestionsInfo implements android.os.Parcelable {
     ctor public SuggestionsInfo(int, java.lang.String[]);
     ctor public SuggestionsInfo(int, java.lang.String[], int, int);
@@ -24136,7 +24316,7 @@
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int RESULT_ATTR_IN_THE_DICTIONARY = 1; // 0x1
-    field public static final int RESULT_ATTR_LOOKS_TYPO = 2; // 0x2
+    field public static final int RESULT_ATTR_LOOKS_LIKE_TYPO = 2; // 0x2
   }
 
   public final class TextInfo implements android.os.Parcelable {
@@ -24152,7 +24332,7 @@
   }
 
   public final class TextServicesManager {
-    method public android.view.textservice.SpellCheckerSession newSpellCheckerSession(java.util.Locale, android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener, boolean);
+    method public android.view.textservice.SpellCheckerSession newSpellCheckerSession(android.os.Bundle, java.util.Locale, android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener, boolean);
   }
 
 }
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index 5fe3644..57e0583 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -32,10 +32,9 @@
 
     /**
      * Starts this animation. If the animation has a nonzero startDelay, the animation will start
-     * running after that delay elapses. Note that the animation does not start synchronously with
-     * this call, because all animation events are posted to a central timing loop so that animation
-     * times are all synchronized on a single timing pulse on the UI thread. So the animation will
-     * start the next time that event handler processes events.
+     * running after that delay elapses. A non-delayed animation will have its initial
+     * value(s) set immediately, followed by calls to
+     * {@link AnimatorListener#onAnimationStart(Animator)} for any listeners of this animator.
      *
      * <p>The animation started by calling this method will be run on the thread that called
      * this method. This thread should have a Looper on it (a runtime exception will be thrown if
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 61a12ee..ce3dd13 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -349,7 +349,8 @@
                 return true;
             }
         }
-        return false;
+        // Also return true if we're currently running the startDelay animator
+        return (mDelayAnim != null && mDelayAnim.isRunning());
     }
 
     /**
@@ -487,7 +488,6 @@
                 mPlayingSet.add(node.animation);
             }
         } else {
-            // TODO: Need to cancel out of the delay appropriately
             mDelayAnim = ValueAnimator.ofFloat(0f, 1f);
             mDelayAnim.setDuration(mStartDelay);
             mDelayAnim.addListener(new AnimatorListenerAdapter() {
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 90d676e..c22306a 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -186,6 +186,16 @@
     int mPlayingState = STOPPED;
 
     /**
+     * Additional playing state to indicate whether an animator has been start()'d. There is
+     * some lag between a call to start() and the first animation frame. We should still note
+     * that the animation has been started, even if it's first animation frame has not yet
+     * happened, and reflect that state in isRunning().
+     * Note that delayed animations are different: they are not started until their first
+     * animation frame, which occurs after their delay elapses.
+     */
+    private boolean mStarted = false;
+
+    /**
      * Flag that denotes whether the animation is set up and ready to go. Used to
      * set up animation that has not yet been started.
      */
@@ -618,6 +628,7 @@
                         for (int i = 0; i < numReadyAnims; ++i) {
                             ValueAnimator anim = readyAnims.get(i);
                             anim.startAnimation();
+                            anim.mStarted = true;
                             delayedAnims.remove(anim);
                         }
                         readyAnims.clear();
@@ -908,6 +919,7 @@
             // This sets the initial value of the animation, prior to actually starting it running
             setCurrentPlayTime(getCurrentPlayTime());
             mPlayingState = STOPPED;
+            mStarted = true;
 
             if (mListeners != null) {
                 ArrayList<AnimatorListener> tmpListeners =
@@ -937,7 +949,8 @@
         // to run
         if (mPlayingState != STOPPED || sPendingAnimations.get().contains(this) ||
                 sDelayedAnims.get().contains(this)) {
-            if (mListeners != null) {
+            // Only notify listeners if the animator has actually started
+            if (mStarted && mListeners != null) {
                 ArrayList<AnimatorListener> tmpListeners =
                         (ArrayList<AnimatorListener>) mListeners.clone();
                 for (AnimatorListener listener : tmpListeners) {
@@ -969,7 +982,7 @@
 
     @Override
     public boolean isRunning() {
-        return (mPlayingState == RUNNING);
+        return (mPlayingState == RUNNING || mStarted);
     }
 
     /**
@@ -1000,7 +1013,7 @@
         sPendingAnimations.get().remove(this);
         sDelayedAnims.get().remove(this);
         mPlayingState = STOPPED;
-        if (mListeners != null) {
+        if (mStarted && mListeners != null) {
             ArrayList<AnimatorListener> tmpListeners =
                     (ArrayList<AnimatorListener>) mListeners.clone();
             int numListeners = tmpListeners.size();
@@ -1008,6 +1021,7 @@
                 tmpListeners.get(i).onAnimationEnd(this);
             }
         }
+        mStarted = false;
     }
 
     /**
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index d5b669e..98b867d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4399,6 +4399,9 @@
         if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
             mWindow.setSoftInputMode(info.softInputMode);
         }
+        if (info.uiOptions != 0) {
+            mWindow.setUiOptions(info.uiOptions);
+        }
         mUiThread = Thread.currentThread();
         
         mMainThread = aThread;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d207a0a..f7e5cf1 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -864,6 +864,15 @@
          */
         public boolean lowMemory;
 
+        /** @hide */
+        public long hiddenAppThreshold;
+        /** @hide */
+        public long secondaryServerThreshold;
+        /** @hide */
+        public long visibleAppThreshold;
+        /** @hide */
+        public long foregroundAppThreshold;
+
         public MemoryInfo() {
         }
 
@@ -875,12 +884,20 @@
             dest.writeLong(availMem);
             dest.writeLong(threshold);
             dest.writeInt(lowMemory ? 1 : 0);
+            dest.writeLong(hiddenAppThreshold);
+            dest.writeLong(secondaryServerThreshold);
+            dest.writeLong(visibleAppThreshold);
+            dest.writeLong(foregroundAppThreshold);
         }
         
         public void readFromParcel(Parcel source) {
             availMem = source.readLong();
             threshold = source.readLong();
             lowMemory = source.readInt() != 0;
+            hiddenAppThreshold = source.readLong();
+            secondaryServerThreshold = source.readLong();
+            visibleAppThreshold = source.readLong();
+            foregroundAppThreshold = source.readLong();
         }
 
         public static final Creator<MemoryInfo> CREATOR
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index b7cd829..a73e10a 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1523,6 +1523,15 @@
             return true;
         }
 
+        case GET_PROCESS_PSS_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            int[] pids = data.createIntArray();
+            long[] pss = getProcessPss(pids);
+            reply.writeNoException();
+            reply.writeLongArray(pss);
+            return true;
+        }
+
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -3432,5 +3441,18 @@
         reply.recycle();
     }
 
+    public long[] getProcessPss(int[] pids) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeIntArray(pids);
+        mRemote.transact(GET_PROCESS_PSS_TRANSACTION, data, reply, 0);
+        reply.readException();
+        long[] res = reply.createLongArray();
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8931675..d5f630a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -729,17 +729,19 @@
         }
 
         @Override
-        public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) {
+        public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, boolean checkin,
+                boolean all, String[] args) {
             FileOutputStream fout = new FileOutputStream(fd);
             PrintWriter pw = new PrintWriter(fout);
             try {
-                return dumpMemInfo(pw, args);
+                return dumpMemInfo(pw, checkin, all, args);
             } finally {
                 pw.flush();
             }
         }
 
-        private Debug.MemoryInfo dumpMemInfo(PrintWriter pw, String[] args) {
+        private Debug.MemoryInfo dumpMemInfo(PrintWriter pw, boolean checkin, boolean all,
+                String[] args) {
             long nativeMax = Debug.getNativeHeapSize() / 1024;
             long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
             long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
@@ -747,6 +749,10 @@
             Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
             Debug.getMemoryInfo(memInfo);
 
+            if (!all) {
+                return memInfo;
+            }
+
             Runtime runtime = Runtime.getRuntime();
 
             long dalvikMax = runtime.totalMemory() / 1024;
@@ -765,16 +771,8 @@
             long sqliteAllocated = SQLiteDebug.getHeapAllocatedSize() / 1024;
             SQLiteDebug.PagerStats stats = SQLiteDebug.getDatabaseInfo();
 
-            // Check to see if we were called by checkin server. If so, print terse format.
-            boolean doCheckinFormat = false;
-            if (args != null) {
-                for (String arg : args) {
-                    if ("-c".equals(arg)) doCheckinFormat = true;
-                }
-            }
-
             // For checkin, we print one long comma-separated list of values
-            if (doCheckinFormat) {
+            if (checkin) {
                 // NOTE: if you change anything significant below, also consider changing
                 // ACTIVITY_THREAD_CHECKIN_VERSION.
                 String processName = (mBoundApplication != null)
@@ -841,13 +839,17 @@
                 pw.print(sqliteAllocated); pw.print(',');
                 pw.print(stats.memoryUsed / 1024); pw.print(',');
                 pw.print(stats.pageCacheOverflo / 1024); pw.print(',');
-                pw.print(stats.largestMemAlloc / 1024); pw.print(',');
+                pw.print(stats.largestMemAlloc / 1024);
                 for (int i = 0; i < stats.dbStats.size(); i++) {
                     DbStats dbStats = stats.dbStats.get(i);
-                    printRow(pw, DB_INFO_FORMAT, dbStats.pageSize, dbStats.dbSize,
-                            dbStats.lookaside, dbStats.cache, dbStats.dbName);
-                    pw.print(',');
+                    pw.print(','); pw.print(dbStats.dbName);
+                    pw.print(','); pw.print(dbStats.pageSize);
+                    pw.print(','); pw.print(dbStats.dbSize);
+                    pw.print(','); pw.print(dbStats.lookaside);
+                    pw.print(','); pw.print(dbStats.cache);
+                    pw.print(','); pw.print(dbStats.cache);
                 }
+                pw.println();
 
                 return memInfo;
             }
@@ -2503,6 +2505,7 @@
                     mAvailThumbnailBitmap = thumbnail;
                     thumbnail = null;
                 }
+                cv.setBitmap(null);
             }
 
         } catch (Exception e) {
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 9a5b527..bea057e 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -491,11 +491,13 @@
         {
             data.enforceInterface(IApplicationThread.descriptor);
             ParcelFileDescriptor fd = data.readFileDescriptor();
+            boolean checkin = data.readInt() != 0;
+            boolean all = data.readInt() != 0;
             String[] args = data.readStringArray();
             Debug.MemoryInfo mi = null;
             if (fd != null) {
                 try {
-                    mi = dumpMemInfo(fd.getFileDescriptor(), args);
+                    mi = dumpMemInfo(fd.getFileDescriptor(), checkin, all, args);
                 } finally {
                     try {
                         fd.close();
@@ -1049,11 +1051,14 @@
                 IBinder.FLAG_ONEWAY);
     }
 
-    public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) throws RemoteException {
+    public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, boolean checkin, boolean all,
+            String[] args) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeFileDescriptor(fd);
+        data.writeInt(checkin ? 1 : 0);
+        data.writeInt(all ? 1 : 0);
         data.writeStringArray(args);
         mRemote.transact(DUMP_MEM_INFO_TRANSACTION, data, reply, 0);
         reply.readException();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 64d77e8..b1b0583 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -364,7 +364,9 @@
     public boolean isIntentSenderTargetedToPackage(IIntentSender sender) throws RemoteException;
 
     public void updatePersistentConfiguration(Configuration values) throws RemoteException;
-    
+
+    public long[] getProcessPss(int[] pids) throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -593,4 +595,5 @@
     int UNREGISTER_PROCESS_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+133;
     int IS_INTENT_SENDER_TARGETED_TO_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+134;
     int UPDATE_PERSISTENT_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+135;
+    int GET_PROCESS_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+136;
 }
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index d0607d0..3a8eb28 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -120,7 +120,8 @@
     void setCoreSettings(Bundle coreSettings) throws RemoteException;
     void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) throws RemoteException;
     void scheduleTrimMemory(int level) throws RemoteException;
-    Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) throws RemoteException;
+    Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, boolean checkin, boolean all,
+            String[] args) throws RemoteException;
     void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException;
 
     String descriptor = "android.app.IApplicationThread";
diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java
index 7b9bd60..8eb9ba4 100644
--- a/core/java/android/app/LauncherActivity.java
+++ b/core/java/android/app/LauncherActivity.java
@@ -314,6 +314,7 @@
                     icon.draw(canvas);
                     icon.setBounds(mOldBounds);
                     icon = new BitmapDrawable(getResources(), thumb);
+                    canvas.setBitmap(null);
                 } else if (iconWidth < width && iconHeight < height) {
                     final Bitmap.Config c = Bitmap.Config.ARGB_8888;
                     final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c);
@@ -326,6 +327,7 @@
                     icon.draw(canvas);
                     icon.setBounds(mOldBounds);
                     icon = new BitmapDrawable(getResources(), thumb);
+                    canvas.setBitmap(null);
                 }
             }
 
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index ca6f085..28bc424 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1163,7 +1163,10 @@
      * <p> If this API returns true, it means the callback will be called.
      * The callback will be called with the current state of Bluetooth.
      * If the state is not what was requested, an internal error would be the
-     * reason.
+     * reason. If Bluetooth is already on and if this function is called to turn
+     * it on, the api will return true and a callback will be called.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
      *
      * @param on True for on, false for off.
      * @param callback The callback to notify changes to the state.
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 4858f14..bba329d 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -433,7 +433,19 @@
      * the mode from the theme will be used.
      */
     public int softInputMode;
-    
+
+    /**
+     * The desired extra UI options for this activity and its main window.
+     * Set from the {@link android.R.attr#uiOptions} attribute in the
+     * activity's manifest.
+     */
+    public int uiOptions = 0;
+
+    /**
+     * Flag for use with uiOptions.
+     */
+    public static final int UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW = 1;
+
     public ActivityInfo() {
     }
 
@@ -448,6 +460,7 @@
         screenOrientation = orig.screenOrientation;
         configChanges = orig.configChanges;
         softInputMode = orig.softInputMode;
+        uiOptions = orig.uiOptions;
     }
     
     /**
@@ -479,6 +492,9 @@
                     + " configChanges=0x" + Integer.toHexString(configChanges)
                     + " softInputMode=0x" + Integer.toHexString(softInputMode));
         }
+        if (uiOptions != 0) {
+            pw.println(prefix + " uiOptions=0x" + Integer.toHexString(uiOptions));
+        }
         super.dumpBack(pw, prefix);
     }
     
@@ -503,6 +519,7 @@
         dest.writeInt(screenOrientation);
         dest.writeInt(configChanges);
         dest.writeInt(softInputMode);
+        dest.writeInt(uiOptions);
     }
 
     public static final Parcelable.Creator<ActivityInfo> CREATOR
@@ -526,5 +543,6 @@
         screenOrientation = source.readInt();
         configChanges = source.readInt();
         softInputMode = source.readInt();
+        uiOptions = source.readInt();
     }
 }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index ddb6ef0..65a8750 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -91,6 +91,13 @@
     public String backupAgentName;
 
     /**
+     * The default extra UI options for activities in this application.
+     * Set from the {@link android.R.attr#uiOptions} attribute in the
+     * activity's manifest.
+     */
+    public int uiOptions = 0;
+
+    /**
      * Value for {@link #flags}: if set, this application is installed in the
      * device's system image.
      */
@@ -456,6 +463,9 @@
         if (descriptionRes != 0) {
             pw.println(prefix + "description=0x"+Integer.toHexString(descriptionRes));
         }
+        if (uiOptions != 0) {
+            pw.println(prefix + "uiOptions=0x" + Integer.toHexString(uiOptions));
+        }
         super.dumpBack(pw, prefix);
     }
     
@@ -509,6 +519,7 @@
         installLocation = orig.installLocation;
         manageSpaceActivityName = orig.manageSpaceActivityName;
         descriptionRes = orig.descriptionRes;
+        uiOptions = orig.uiOptions;
     }
 
 
@@ -547,6 +558,7 @@
         dest.writeString(manageSpaceActivityName);
         dest.writeString(backupAgentName);
         dest.writeInt(descriptionRes);
+        dest.writeInt(uiOptions);
     }
 
     public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -584,6 +596,7 @@
         manageSpaceActivityName = source.readString();
         backupAgentName = source.readString();
         descriptionRes = source.readInt();
+        uiOptions = source.readInt();
     }
 
     /**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 53d6bb1..22fdc98 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -598,7 +598,12 @@
             assmgr = new AssetManager();
             assmgr.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                     Build.VERSION.RESOURCES_SDK_INT);
+
             int cookie = assmgr.addAssetPath(packageFilePath);
+            if (cookie == 0) {
+                return null;
+            }
+
             parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml");
         } catch (Exception e) {
             if (assmgr != null) assmgr.close();
@@ -1645,6 +1650,9 @@
             }
         }
 
+        ai.uiOptions = sa.getInt(
+                com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0);
+
         sa.recycle();
 
         if (outError[0] != null) {
@@ -1850,6 +1858,10 @@
         a.info.theme = sa.getResourceId(
                 com.android.internal.R.styleable.AndroidManifestActivity_theme, 0);
 
+        a.info.uiOptions = sa.getInt(
+                com.android.internal.R.styleable.AndroidManifestActivity_uiOptions,
+                a.info.applicationInfo.uiOptions);
+
         String str;
         str = sa.getNonConfigurationString(
                 com.android.internal.R.styleable.AndroidManifestActivity_permission, 0);
@@ -2091,6 +2103,7 @@
         info.screenOrientation = target.info.screenOrientation;
         info.taskAffinity = target.info.taskAffinity;
         info.theme = target.info.theme;
+        info.uiOptions = target.info.uiOptions;
         
         Activity a = new Activity(mParseActivityAliasArgs, info);
         if (outError[0] != null) {
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 6767747..58c79fc 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1708,6 +1708,7 @@
         private static final String PIXEL_FORMAT_YUV420P = "yuv420p";
         private static final String PIXEL_FORMAT_RGB565 = "rgb565";
         private static final String PIXEL_FORMAT_JPEG = "jpeg";
+        private static final String PIXEL_FORMAT_BAYER_RGGB = "bayer-rggb";
 
         private HashMap<String, String> mMap;
 
@@ -2258,6 +2259,7 @@
             case ImageFormat.YV12:      return PIXEL_FORMAT_YUV420P;
             case ImageFormat.RGB_565:   return PIXEL_FORMAT_RGB565;
             case ImageFormat.JPEG:      return PIXEL_FORMAT_JPEG;
+            case ImageFormat.BAYER_RGGB: return PIXEL_FORMAT_BAYER_RGGB;
             default:                    return null;
             }
         }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a564d97..eb9cd21 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -16,10 +16,11 @@
 
 package android.net;
 
+import static com.android.internal.util.Preconditions.checkNotNull;
+
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.os.Binder;
-import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 
 import java.net.InetAddress;
@@ -67,11 +68,19 @@
      * is set to {@code true} if there are no connected networks at all.
      */
     public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
+
     /**
      * The lookup key for a {@link NetworkInfo} object. Retrieve with
      * {@link android.content.Intent#getParcelableExtra(String)}.
+     *
+     * @deprecated Since {@link NetworkInfo} can vary based on UID, applications
+     *             should always obtain network information through
+     *             {@link #getActiveNetworkInfo()} or
+     *             {@link #getAllNetworkInfo()}.
      */
+    @Deprecated
     public static final String EXTRA_NETWORK_INFO = "networkInfo";
+
     /**
      * The lookup key for a boolean that indicates whether a connect event
      * is for a network to which the connectivity manager was failing over
@@ -515,6 +524,19 @@
     }
 
     /**
+     * Return quota status for the current active network, or {@code null} if no
+     * network is active. Quota status can change rapidly, so these values
+     * shouldn't be cached.
+     */
+    public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
+        try {
+            return mService.getActiveNetworkQuotaInfo();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
      * Gets the value of the setting for enabling Mobile data.
      *
      * @return Whether mobile data is enabled.
@@ -546,10 +568,7 @@
      * {@hide}
      */
     public ConnectivityManager(IConnectivityManager service) {
-        if (service == null) {
-            throw new IllegalArgumentException("missing IConnectivityManager");
-        }
-        mService = service;
+        mService = checkNotNull(service, "missing IConnectivityManager");
     }
 
     /**
diff --git a/core/java/android/net/DnsPinger.java b/core/java/android/net/DnsPinger.java
index f2d84eb..81738f3 100644
--- a/core/java/android/net/DnsPinger.java
+++ b/core/java/android/net/DnsPinger.java
@@ -17,20 +17,27 @@
 package android.net;
 
 import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.LinkProperties;
-import android.net.NetworkUtils;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
 import android.os.SystemClock;
 import android.provider.Settings;
 import android.util.Slog;
 
+import com.android.internal.util.Protocol;
+
+import java.io.IOException;
 import java.net.DatagramPacket;
 import java.net.DatagramSocket;
 import java.net.InetAddress;
 import java.net.NetworkInterface;
 import java.net.SocketTimeoutException;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
 import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Performs a simple DNS "ping" by sending a "server status" query packet to the
@@ -40,42 +47,174 @@
  * API may not differentiate between a time out and a failure lookup (which we
  * really care about).
  * <p>
- * TODO : More general API. Socket does not bind to specified connection type
- * TODO : Choice of DNS query location - current looks up www.android.com
  *
  * @hide
  */
-public final class DnsPinger {
+public final class DnsPinger extends Handler {
     private static final boolean V = true;
 
-    /** Number of bytes for the query */
-    private static final int DNS_QUERY_BASE_SIZE = 32;
-
-    /** The DNS port */
+    private static final int RECEIVE_POLL_INTERVAL_MS = 30;
     private static final int DNS_PORT = 53;
 
+    /** Short socket timeout so we don't block one any 'receive' call */
+    private static final int SOCKET_TIMEOUT_MS = 1;
+
     /** Used to generate IDs */
-    private static Random sRandom = new Random();
+    private static final Random sRandom = new Random();
+    private static final AtomicInteger sCounter = new AtomicInteger();
 
     private ConnectivityManager mConnectivityManager = null;
-    private Context mContext;
-    private int mConnectionType;
-    private InetAddress mDefaultDns;
-
+    private final Context mContext;
+    private final int mConnectionType;
+    private final Handler mTarget;
+    private final InetAddress mDefaultDns;
     private String TAG;
 
+    private static final int BASE = Protocol.BASE_DNS_PINGER;
+
     /**
-     * @param connectionType The connection type from {@link ConnectivityManager}
+     * Async response packet for dns pings.
+     * arg1 is the ID of the ping, also returned by {@link #pingDnsAsync(InetAddress, int, int)}
+     * arg2 is the delay, or is negative on error.
      */
-    public DnsPinger(String TAG, Context context, int connectionType) {
+    public static final int DNS_PING_RESULT = BASE;
+    /** An error code for a {@link #DNS_PING_RESULT} packet */
+    public static final int TIMEOUT = -1;
+    /** An error code for a {@link #DNS_PING_RESULT} packet */
+    public static final int SOCKET_EXCEPTION = -2;
+
+    /**
+     * Send a new ping via a socket.  arg1 is ID, arg2 is timeout, obj is InetAddress to ping
+     */
+    private static final int ACTION_PING_DNS = BASE + 1;
+    private static final int ACTION_LISTEN_FOR_RESPONSE = BASE + 2;
+    private static final int ACTION_CANCEL_ALL_PINGS = BASE + 3;
+
+    private List<ActivePing> mActivePings = new ArrayList<ActivePing>();
+    private int mEventCounter;
+
+    private class ActivePing {
+        DatagramSocket socket;
+        int internalId;
+        short packetId;
+        int timeout;
+        Integer result;
+        long start = SystemClock.elapsedRealtime();
+    }
+
+    public DnsPinger(Context context, String TAG, Looper looper,
+            Handler target, int connectionType) {
+        super(looper);
+        this.TAG = TAG;
         mContext = context;
+        mTarget = target;
         mConnectionType = connectionType;
         if (!ConnectivityManager.isNetworkTypeValid(connectionType)) {
-            Slog.e(TAG, "Invalid connectionType in constructor: " + connectionType);
+            throw new IllegalArgumentException("Invalid connectionType in constructor: "
+                    + connectionType);
         }
-        this.TAG = TAG;
-
         mDefaultDns = getDefaultDns();
+        mEventCounter = 0;
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        switch (msg.what) {
+            case ACTION_PING_DNS:
+                try {
+                    ActivePing newActivePing = new ActivePing();
+                    InetAddress dnsAddress = (InetAddress) msg.obj;
+                    newActivePing.internalId = msg.arg1;
+                    newActivePing.timeout = msg.arg2;
+                    newActivePing.socket = new DatagramSocket();
+                    // Set some socket properties
+                    newActivePing.socket.setSoTimeout(SOCKET_TIMEOUT_MS);
+
+                    // Try to bind but continue ping if bind fails
+                    try {
+                        newActivePing.socket.setNetworkInterface(NetworkInterface.getByName(
+                                getCurrentLinkProperties().getInterfaceName()));
+                    } catch (Exception e) {
+                        Slog.w(TAG,"sendDnsPing::Error binding to socket", e);
+                    }
+
+                    newActivePing.packetId = (short) sRandom.nextInt();
+                    byte[] buf = mDnsQuery.clone();
+                    buf[0] = (byte) (newActivePing.packetId >> 8);
+                    buf[1] = (byte) newActivePing.packetId;
+
+                    // Send the DNS query
+                    DatagramPacket packet = new DatagramPacket(buf,
+                            buf.length, dnsAddress, DNS_PORT);
+                    if (V) {
+                        Slog.v(TAG, "Sending a ping to " + dnsAddress.getHostAddress()
+                                + " with ID " + newActivePing.packetId + ".");
+                    }
+
+                    newActivePing.socket.send(packet);
+                    mActivePings.add(newActivePing);
+                    mEventCounter++;
+                    sendMessageDelayed(obtainMessage(ACTION_LISTEN_FOR_RESPONSE, mEventCounter, 0),
+                            RECEIVE_POLL_INTERVAL_MS);
+                } catch (IOException e) {
+                    sendResponse((short) msg.arg1, SOCKET_EXCEPTION);
+                }
+                break;
+            case ACTION_LISTEN_FOR_RESPONSE:
+                if (msg.arg1 != mEventCounter) {
+                    break;
+                }
+                for (ActivePing curPing : mActivePings) {
+                    try {
+                        /** Each socket will block for {@link #SOCKET_TIMEOUT_MS} in receive() */
+                        byte[] responseBuf = new byte[2];
+                        DatagramPacket replyPacket = new DatagramPacket(responseBuf, 2);
+                        curPing.socket.receive(replyPacket);
+                        // Check that ID field matches (we're throwing out the rest of the packet)
+                        if (responseBuf[0] == (byte) (curPing.packetId >> 8) &&
+                                responseBuf[1] == (byte) curPing.packetId) {
+                            curPing.result =
+                                    (int) (SystemClock.elapsedRealtime() - curPing.start);
+                        } else {
+                            if (V) {
+                                Slog.v(TAG, "response ID didn't match, ignoring packet");
+                            }
+                        }
+                    } catch (SocketTimeoutException e) {
+                        // A timeout here doesn't mean anything - squelsh this exception
+                    } catch (Exception e) {
+                        if (V) {
+                            Slog.v(TAG, "DnsPinger.pingDns got socket exception: ", e);
+                        }
+                        curPing.result = SOCKET_EXCEPTION;
+                    }
+                }
+                Iterator<ActivePing> iter = mActivePings.iterator();
+                while (iter.hasNext()) {
+                   ActivePing curPing = iter.next();
+                   if (curPing.result != null) {
+                       sendResponse(curPing.internalId, curPing.result);
+                       curPing.socket.close();
+                       iter.remove();
+                   } else if (SystemClock.elapsedRealtime() >
+                                  curPing.start + curPing.timeout) {
+                       sendResponse(curPing.internalId, TIMEOUT);
+                       curPing.socket.close();
+                       iter.remove();
+                   }
+                }
+                if (!mActivePings.isEmpty()) {
+                    sendMessageDelayed(obtainMessage(ACTION_LISTEN_FOR_RESPONSE, mEventCounter, 0),
+                            RECEIVE_POLL_INTERVAL_MS);
+                }
+                break;
+            case ACTION_CANCEL_ALL_PINGS:
+                for (ActivePing activePing : mActivePings)
+                    activePing.socket.close();
+                mActivePings.clear();
+                removeMessages(ACTION_PING_DNS);
+                break;
+        }
     }
 
     /**
@@ -99,6 +238,30 @@
         return dnses.iterator().next();
     }
 
+    /**
+     * Send a ping.  The response will come via a {@link #DNS_PING_RESULT} to the handler
+     * specified at creation.
+     * @param dns address of dns server to ping
+     * @param timeout timeout for ping
+     * @return an ID field, which will also be included in the {@link #DNS_PING_RESULT} message.
+     */
+    public int pingDnsAsync(InetAddress dns, int timeout, int delay) {
+        int id = sCounter.incrementAndGet();
+        sendMessageDelayed(obtainMessage(ACTION_PING_DNS, id, timeout, dns), delay);
+        return id;
+    }
+
+    public void cancelPings() {
+        obtainMessage(ACTION_CANCEL_ALL_PINGS).sendToTarget();
+    }
+
+    private void sendResponse(int internalId, int responseVal) {
+        if(V) {
+            Slog.v(TAG, "Responding with id " + internalId + " and val " + responseVal);
+        }
+        mTarget.sendMessage(obtainMessage(DNS_PING_RESULT, internalId, responseVal));
+    }
+
     private LinkProperties getCurrentLinkProperties() {
         if (mConnectivityManager == null) {
             mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
@@ -123,106 +286,18 @@
         }
     }
 
-    /**
-     * @return time to response. Negative value on error.
-     */
-    public long pingDns(InetAddress dnsAddress, int timeout) {
-        DatagramSocket socket = null;
-        try {
-            socket = new DatagramSocket();
-
-            // Set some socket properties
-            socket.setSoTimeout(timeout);
-
-            // Try to bind but continue ping if bind fails
-            try {
-                socket.setNetworkInterface(NetworkInterface.getByName(
-                        getCurrentLinkProperties().getInterfaceName()));
-            } catch (Exception e) {
-                Slog.d(TAG,"pingDns::Error binding to socket", e);
-            }
-
-            byte[] buf = constructQuery();
-
-            // Send the DNS query
-
-            DatagramPacket packet = new DatagramPacket(buf,
-                    buf.length, dnsAddress, DNS_PORT);
-            long start = SystemClock.elapsedRealtime();
-            socket.send(packet);
-
-            // Wait for reply (blocks for the above timeout)
-            DatagramPacket replyPacket = new DatagramPacket(buf, buf.length);
-            socket.receive(replyPacket);
-
-            // If a timeout occurred, an exception would have been thrown. We
-            // got a reply!
-            return SystemClock.elapsedRealtime() - start;
-
-        } catch (SocketTimeoutException e) {
-            // Squelch this exception.
-            return -1;
-        } catch (Exception e) {
-            if (V) {
-                Slog.v(TAG, "DnsPinger.pingDns got socket exception: ", e);
-            }
-            return -2;
-        } finally {
-            if (socket != null) {
-                socket.close();
-            }
-        }
-
-    }
-
-    /**
-     * @return google.com DNS query packet
-     */
-    private static byte[] constructQuery() {
-        byte[] buf = new byte[DNS_QUERY_BASE_SIZE];
-
-        // [0-1] bytes are an ID, generate random ID for this query
-        buf[0] = (byte) sRandom.nextInt(256);
-        buf[1] = (byte) sRandom.nextInt(256);
-
-        // [2-3] bytes are for flags.
-        buf[2] = 0x01; // Recursion desired
-
-        // [4-5] bytes are for number of queries (QCOUNT)
-        buf[5] = 0x01;
-
-        // [6-7] [8-9] [10-11] are all counts of other fields we don't use
-
-        // [12-15] for www
-        writeString(buf, 12, "www");
-
-        // [16-22] for google
-        writeString(buf, 16, "google");
-
-        // [23-26] for com
-        writeString(buf, 23, "com");
-
-        // [27] is a null byte terminator byte for the url
-
-        // [28-29] bytes are for QTYPE, set to 1 = A (host address)
-        buf[29] = 0x01;
-
-        // [30-31] bytes are for QCLASS, set to 1 = IN (internet)
-        buf[31] = 0x01;
-
-        return buf;
-    }
-
-    /**
-     * Writes the string's length and its contents to the buffer
-     */
-    private static void writeString(byte[] buf, int startPos, String string) {
-        int pos = startPos;
-
-        // Write the length first
-        buf[pos++] = (byte) string.length();
-        for (int i = 0; i < string.length(); i++) {
-            buf[pos++] = (byte) string.charAt(i);
-        }
-    }
+    private static final byte[] mDnsQuery = new byte[] {
+        0, 0, // [0-1] is for ID (will set each time)
+        0, 0, // [2-3] are flags.  Set byte[2] = 1 for recursion desired (RD) on.  Currently off. 
+        0, 1, // [4-5] bytes are for number of queries (QCOUNT)
+        0, 0, // [6-7] unused count field for dns response packets
+        0, 0, // [8-9] unused count field for dns response packets
+        0, 0, // [10-11] unused count field for dns response packets
+        3, 'w', 'w', 'w',
+        6, 'g', 'o', 'o', 'g', 'l', 'e',
+        3, 'c', 'o', 'm',
+        0,    // null terminator of address (also called empty TLD)
+        0, 1, // QTYPE, set to 1 = A (host address)
+        0, 1  // QCLASS, set to 1 = IN (internet)
+    };
 }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index b1d99a4..f391200 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -18,6 +18,7 @@
 
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
+import android.net.NetworkQuotaInfo;
 import android.net.NetworkState;
 import android.net.ProxyProperties;
 import android.os.IBinder;
@@ -47,6 +48,8 @@
 
     NetworkState[] getAllNetworkState();
 
+    NetworkQuotaInfo getActiveNetworkQuotaInfo();
+
     boolean setRadios(boolean onOff);
 
     boolean setRadio(int networkType, boolean turnOn);
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 3e07b0a..633c38e0 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -18,6 +18,8 @@
 
 import android.net.INetworkPolicyListener;
 import android.net.NetworkPolicy;
+import android.net.NetworkQuotaInfo;
+import android.net.NetworkState;
 import android.net.NetworkTemplate;
 
 /**
@@ -27,6 +29,7 @@
  */
 interface INetworkPolicyManager {
 
+    /** Control UID policies. */
     void setUidPolicy(int uid, int policy);
     int getUidPolicy(int uid);
 
@@ -35,12 +38,17 @@
     void registerListener(INetworkPolicyListener listener);
     void unregisterListener(INetworkPolicyListener listener);
 
+    /** Control network policies atomically. */
     void setNetworkPolicies(in NetworkPolicy[] policies);
     NetworkPolicy[] getNetworkPolicies();
 
+    /** Snooze limit on policy matching given template. */
     void snoozePolicy(in NetworkTemplate template);
 
+    /** Control if background data is restricted system-wide. */
     void setRestrictBackground(boolean restrictBackground);
     boolean getRestrictBackground();
 
+    NetworkQuotaInfo getNetworkQuotaInfo(in NetworkState state);
+
 }
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index c41d182..b65506c 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -24,9 +24,9 @@
 interface INetworkStatsService {
 
     /** Return historical network layer stats for traffic that matches template. */
-    NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template);
+    NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields);
     /** Return historical network layer stats for specific UID traffic that matches template. */
-    NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int tag);
+    NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int tag, int fields);
 
     /** Return network layer usage summary for traffic that matches template. */
     NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end);
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 7336550..5501f38 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -119,22 +119,22 @@
             switch (msg.what) {
                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
                     if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
-                        if (DBG) {
+                        if (VDBG) {
                             mMdst.log("MdstHandler connected");
                         }
                         mMdst.mDataConnectionTrackerAc = (AsyncChannel) msg.obj;
                     } else {
-                        if (DBG) {
+                        if (VDBG) {
                             mMdst.log("MdstHandler %s NOT connected error=" + msg.arg1);
                         }
                     }
                     break;
                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
-                    mMdst.log("Disconnected from DataStateTracker");
+                    if (VDBG) mMdst.log("Disconnected from DataStateTracker");
                     mMdst.mDataConnectionTrackerAc = null;
                     break;
                 default: {
-                    mMdst.log("Ignorning unknown message=" + msg);
+                    if (VDBG) mMdst.log("Ignorning unknown message=" + msg);
                     break;
                 }
             }
@@ -221,13 +221,13 @@
                             mLinkProperties = intent.getParcelableExtra(
                                     Phone.DATA_LINK_PROPERTIES_KEY);
                             if (mLinkProperties == null) {
-                                log("CONNECTED event did not supply link properties.");
+                                loge("CONNECTED event did not supply link properties.");
                                 mLinkProperties = new LinkProperties();
                             }
                             mLinkCapabilities = intent.getParcelableExtra(
                                     Phone.DATA_LINK_CAPABILITIES_KEY);
                             if (mLinkCapabilities == null) {
-                                log("CONNECTED event did not supply link capabilities.");
+                                loge("CONNECTED event did not supply link capabilities.");
                                 mLinkCapabilities = new LinkCapabilities();
                             }
                             setDetailedState(DetailedState.CONNECTED, reason, apnName);
@@ -238,7 +238,7 @@
                     if (TextUtils.equals(reason, Phone.REASON_LINK_PROPERTIES_CHANGED)) {
                         mLinkProperties = intent.getParcelableExtra(Phone.DATA_LINK_PROPERTIES_KEY);
                         if (mLinkProperties == null) {
-                            log("No link property in LINK_PROPERTIES change event.");
+                            loge("No link property in LINK_PROPERTIES change event.");
                             mLinkProperties = new LinkProperties();
                         }
                         // Just update reason field in this NetworkInfo
@@ -269,7 +269,7 @@
                 setDetailedState(DetailedState.FAILED, reason, apnName);
             } else if (intent.getAction().
                     equals(DataConnectionTracker.ACTION_DATA_CONNECTION_TRACKER_MESSENGER)) {
-                if (DBG) log(mApnType + " got ACTION_DATA_CONNECTION_TRACKER_MESSENGER");
+                if (VDBG) log(mApnType + " got ACTION_DATA_CONNECTION_TRACKER_MESSENGER");
                 mMessenger = intent.getParcelableExtra(DataConnectionTracker.EXTRA_MESSENGER);
                 AsyncChannel ac = new AsyncChannel();
                 ac.connect(mContext, MobileDataStateTracker.this.mHandler, mMessenger);
@@ -437,7 +437,7 @@
          */
         for (int retry = 0; retry < 2; retry++) {
             if (mPhoneService == null) {
-                log("Ignoring mobile radio request because could not acquire PhoneService");
+                loge("Ignoring mobile radio request because could not acquire PhoneService");
                 break;
             }
 
@@ -448,7 +448,7 @@
             }
         }
 
-        log("Could not set radio power to " + (turnOn ? "on" : "off"));
+        loge("Could not set radio power to " + (turnOn ? "on" : "off"));
         return false;
     }
 
@@ -457,12 +457,12 @@
      */
     public void setDataEnable(boolean enabled) {
         try {
-            log("setDataEnable: E enabled=" + enabled);
+            if (DBG) log("setDataEnable: E enabled=" + enabled);
             mDataConnectionTrackerAc.sendMessage(DataConnectionTracker.CMD_SET_DATA_ENABLE,
                     enabled ? DataConnectionTracker.ENABLED : DataConnectionTracker.DISABLED);
-            log("setDataEnable: X enabled=" + enabled);
+            if (VDBG) log("setDataEnable: X enabled=" + enabled);
         } catch (Exception e) {
-            log("setDataEnable: X mAc was null" + e);
+            loge("setDataEnable: X mAc was null" + e);
         }
     }
 
@@ -473,15 +473,15 @@
     public void setDependencyMet(boolean met) {
         Bundle bundle = Bundle.forPair(DataConnectionTracker.APN_TYPE_KEY, mApnType);
         try {
-            log("setDependencyMet: E met=" + met);
+            if (DBG) log("setDependencyMet: E met=" + met);
             Message msg = Message.obtain();
             msg.what = DataConnectionTracker.CMD_SET_DEPENDENCY_MET;
             msg.arg1 = (met ? DataConnectionTracker.ENABLED : DataConnectionTracker.DISABLED);
             msg.setData(bundle);
             mDataConnectionTrackerAc.sendMessage(msg);
-            log("setDependencyMet: X met=" + met);
+            if (VDBG) log("setDependencyMet: X met=" + met);
         } catch (NullPointerException e) {
-            log("setDependencyMet: X mAc was null" + e);
+            loge("setDependencyMet: X mAc was null" + e);
         }
     }
 
@@ -508,7 +508,7 @@
          */
         for (int retry = 0; retry < 2; retry++) {
             if (mPhoneService == null) {
-                log("Ignoring feature request because could not acquire PhoneService");
+                loge("Ignoring feature request because could not acquire PhoneService");
                 break;
             }
 
@@ -523,7 +523,7 @@
             }
         }
 
-        log("Could not " + (enable ? "enable" : "disable") + " APN type \"" + apnType + "\"");
+        loge("Could not " + (enable ? "enable" : "disable") + " APN type \"" + apnType + "\"");
         return Phone.APN_REQUEST_FAILED;
     }
 
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 1e9d813..9d253c7 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -189,9 +189,10 @@
      */
     public static void snapToCycleDay(Time time, int cycleDay) {
         if (cycleDay > time.getActualMaximum(MONTH_DAY)) {
-            // cycle day isn't valid this month; snap to 1st of next month
+            // cycle day isn't valid this month; snap to last second of month
             time.month += 1;
             time.monthDay = 1;
+            time.second = -1;
         } else {
             time.monthDay = cycleDay;
         }
diff --git a/core/java/android/net/NetworkQuotaInfo.aidl b/core/java/android/net/NetworkQuotaInfo.aidl
new file mode 100644
index 0000000..98a02c4
--- /dev/null
+++ b/core/java/android/net/NetworkQuotaInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.net;
+
+parcelable NetworkQuotaInfo;
diff --git a/core/java/android/net/NetworkQuotaInfo.java b/core/java/android/net/NetworkQuotaInfo.java
new file mode 100644
index 0000000..b85f925
--- /dev/null
+++ b/core/java/android/net/NetworkQuotaInfo.java
@@ -0,0 +1,79 @@
+/*
+ * 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 android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Information about quota status on a specific network.
+ */
+public class NetworkQuotaInfo implements Parcelable {
+    private final long mEstimatedBytes;
+    private final long mSoftLimitBytes;
+    private final long mHardLimitBytes;
+
+    public static final long NO_LIMIT = -1;
+
+    /** {@hide} */
+    public NetworkQuotaInfo(long estimatedBytes, long softLimitBytes, long hardLimitBytes) {
+        mEstimatedBytes = estimatedBytes;
+        mSoftLimitBytes = softLimitBytes;
+        mHardLimitBytes = hardLimitBytes;
+    }
+
+    /** {@hide} */
+    public NetworkQuotaInfo(Parcel in) {
+        mEstimatedBytes = in.readLong();
+        mSoftLimitBytes = in.readLong();
+        mHardLimitBytes = in.readLong();
+    }
+
+    public long getEstimatedBytes() {
+        return mEstimatedBytes;
+    }
+
+    public long getSoftLimitBytes() {
+        return mSoftLimitBytes;
+    }
+
+    public long getHardLimitBytes() {
+        return mHardLimitBytes;
+    }
+
+    /** {@inheritDoc} */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeLong(mEstimatedBytes);
+        out.writeLong(mSoftLimitBytes);
+        out.writeLong(mHardLimitBytes);
+    }
+
+    public static final Creator<NetworkQuotaInfo> CREATOR = new Creator<NetworkQuotaInfo>() {
+        public NetworkQuotaInfo createFromParcel(Parcel in) {
+            return new NetworkQuotaInfo(in);
+        }
+
+        public NetworkQuotaInfo[] newArray(int size) {
+            return new NetworkQuotaInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 0e8e7fc..f2fcb8f 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -58,7 +58,7 @@
     private long[] rxPackets;
     private long[] txBytes;
     private long[] txPackets;
-    private int[] operations;
+    private long[] operations;
 
     public static class Entry {
         public String iface;
@@ -68,13 +68,18 @@
         public long rxPackets;
         public long txBytes;
         public long txPackets;
-        public int operations;
+        public long operations;
 
         public Entry() {
+            this(IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
+        }
+
+        public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
+            this(IFACE_ALL, UID_ALL, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, operations);
         }
 
         public Entry(String iface, int uid, int tag, long rxBytes, long rxPackets, long txBytes,
-                long txPackets, int operations) {
+                long txPackets, long operations) {
             this.iface = iface;
             this.uid = uid;
             this.tag = tag;
@@ -96,7 +101,7 @@
         this.rxPackets = new long[initialSize];
         this.txBytes = new long[initialSize];
         this.txPackets = new long[initialSize];
-        this.operations = new int[initialSize];
+        this.operations = new long[initialSize];
     }
 
     public NetworkStats(Parcel parcel) {
@@ -109,7 +114,7 @@
         rxPackets = parcel.createLongArray();
         txBytes = parcel.createLongArray();
         txPackets = parcel.createLongArray();
-        operations = parcel.createIntArray();
+        operations = parcel.createLongArray();
     }
 
     /** {@inheritDoc} */
@@ -123,16 +128,16 @@
         dest.writeLongArray(rxPackets);
         dest.writeLongArray(txBytes);
         dest.writeLongArray(txPackets);
-        dest.writeIntArray(operations);
+        dest.writeLongArray(operations);
     }
 
     public NetworkStats addValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
             long txBytes, long txPackets) {
-        return addValues(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, 0);
+        return addValues(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, 0L);
     }
 
     public NetworkStats addValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
-            long txBytes, long txPackets, int operations) {
+            long txBytes, long txPackets, long operations) {
         return addValues(
                 new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
     }
@@ -197,7 +202,7 @@
     }
 
     public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
-            long txBytes, long txPackets, int operations) {
+            long txBytes, long txPackets, long operations) {
         return combineValues(
                 new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
     }
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index 4ffabb1..c917af9 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -19,11 +19,11 @@
 import static android.net.NetworkStats.IFACE_ALL;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
-import static android.net.NetworkStatsHistory.DataStreamUtils.readLongArray;
-import static android.net.NetworkStatsHistory.DataStreamUtils.writeLongArray;
-import static android.net.NetworkStatsHistory.ParcelUtils.readIntArray;
+import static android.net.NetworkStatsHistory.DataStreamUtils.readFullLongArray;
+import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLongArray;
+import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLongArray;
+import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
 import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray;
-import static android.net.NetworkStatsHistory.ParcelUtils.writeIntArray;
 import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray;
 
 import android.os.Parcel;
@@ -51,42 +51,53 @@
  */
 public class NetworkStatsHistory implements Parcelable {
     private static final int VERSION_INIT = 1;
+    private static final int VERSION_ADD_PACKETS = 2;
 
-    // TODO: teach about varint encoding to use less disk space
-    // TODO: teach about omitting entire fields to reduce parcel pressure
-    // TODO: persist/restore packet and operation counts
+    public static final int FIELD_RX_BYTES = 0x01;
+    public static final int FIELD_RX_PACKETS = 0x02;
+    public static final int FIELD_TX_BYTES = 0x04;
+    public static final int FIELD_TX_PACKETS = 0x08;
+    public static final int FIELD_OPERATIONS = 0x10;
 
-    private final long bucketDuration;
+    public static final int FIELD_ALL = 0xFFFFFFFF;
+
+    private long bucketDuration;
     private int bucketCount;
     private long[] bucketStart;
     private long[] rxBytes;
     private long[] rxPackets;
     private long[] txBytes;
     private long[] txPackets;
-    private int[] operations;
+    private long[] operations;
 
     public static class Entry {
+        public static final long UNKNOWN = -1;
+
         public long bucketStart;
         public long bucketDuration;
         public long rxBytes;
         public long rxPackets;
         public long txBytes;
         public long txPackets;
-        public int operations;
+        public long operations;
     }
 
     public NetworkStatsHistory(long bucketDuration) {
-        this(bucketDuration, 10);
+        this(bucketDuration, 10, FIELD_ALL);
     }
 
     public NetworkStatsHistory(long bucketDuration, int initialSize) {
+        this(bucketDuration, initialSize, FIELD_ALL);
+    }
+
+    public NetworkStatsHistory(long bucketDuration, int initialSize, int fields) {
         this.bucketDuration = bucketDuration;
         bucketStart = new long[initialSize];
-        rxBytes = new long[initialSize];
-        rxPackets = new long[initialSize];
-        txBytes = new long[initialSize];
-        txPackets = new long[initialSize];
-        operations = new int[initialSize];
+        if ((fields & FIELD_RX_BYTES) != 0) rxBytes = new long[initialSize];
+        if ((fields & FIELD_RX_PACKETS) != 0) rxPackets = new long[initialSize];
+        if ((fields & FIELD_TX_BYTES) != 0) txBytes = new long[initialSize];
+        if ((fields & FIELD_TX_PACKETS) != 0) txPackets = new long[initialSize];
+        if ((fields & FIELD_OPERATIONS) != 0) operations = new long[initialSize];
         bucketCount = 0;
     }
 
@@ -97,7 +108,7 @@
         rxPackets = readLongArray(in);
         txBytes = readLongArray(in);
         txPackets = readLongArray(in);
-        operations = readIntArray(in);
+        operations = readLongArray(in);
         bucketCount = bucketStart.length;
     }
 
@@ -109,21 +120,31 @@
         writeLongArray(out, rxPackets, bucketCount);
         writeLongArray(out, txBytes, bucketCount);
         writeLongArray(out, txPackets, bucketCount);
-        writeIntArray(out, operations, bucketCount);
+        writeLongArray(out, operations, bucketCount);
     }
 
     public NetworkStatsHistory(DataInputStream in) throws IOException {
-        // TODO: read packet and operation counts
         final int version = in.readInt();
         switch (version) {
             case VERSION_INIT: {
                 bucketDuration = in.readLong();
-                bucketStart = readLongArray(in);
-                rxBytes = readLongArray(in);
+                bucketStart = readFullLongArray(in);
+                rxBytes = readFullLongArray(in);
                 rxPackets = new long[bucketStart.length];
-                txBytes = readLongArray(in);
+                txBytes = readFullLongArray(in);
                 txPackets = new long[bucketStart.length];
-                operations = new int[bucketStart.length];
+                operations = new long[bucketStart.length];
+                bucketCount = bucketStart.length;
+                break;
+            }
+            case VERSION_ADD_PACKETS: {
+                bucketDuration = in.readLong();
+                bucketStart = readVarLongArray(in);
+                rxBytes = readVarLongArray(in);
+                rxPackets = readVarLongArray(in);
+                txBytes = readVarLongArray(in);
+                txPackets = readVarLongArray(in);
+                operations = readVarLongArray(in);
                 bucketCount = bucketStart.length;
                 break;
             }
@@ -134,12 +155,14 @@
     }
 
     public void writeToStream(DataOutputStream out) throws IOException {
-        // TODO: write packet and operation counts
-        out.writeInt(VERSION_INIT);
+        out.writeInt(VERSION_ADD_PACKETS);
         out.writeLong(bucketDuration);
-        writeLongArray(out, bucketStart, bucketCount);
-        writeLongArray(out, rxBytes, bucketCount);
-        writeLongArray(out, txBytes, bucketCount);
+        writeVarLongArray(out, bucketStart, bucketCount);
+        writeVarLongArray(out, rxBytes, bucketCount);
+        writeVarLongArray(out, rxPackets, bucketCount);
+        writeVarLongArray(out, txBytes, bucketCount);
+        writeVarLongArray(out, txPackets, bucketCount);
+        writeVarLongArray(out, operations, bucketCount);
     }
 
     /** {@inheritDoc} */
@@ -178,11 +201,11 @@
         final Entry entry = recycle != null ? recycle : new Entry();
         entry.bucketStart = bucketStart[i];
         entry.bucketDuration = bucketDuration;
-        entry.rxBytes = rxBytes[i];
-        entry.rxPackets = rxPackets[i];
-        entry.txBytes = txBytes[i];
-        entry.txPackets = txPackets[i];
-        entry.operations = operations[i];
+        entry.rxBytes = getLong(rxBytes, i, UNKNOWN);
+        entry.rxPackets = getLong(rxPackets, i, UNKNOWN);
+        entry.txBytes = getLong(txBytes, i, UNKNOWN);
+        entry.txPackets = getLong(txPackets, i, UNKNOWN);
+        entry.operations = getLong(operations, i, UNKNOWN);
         return entry;
     }
 
@@ -193,7 +216,7 @@
     @Deprecated
     public void recordData(long start, long end, long rxBytes, long txBytes) {
         recordData(start, end,
-                new NetworkStats.Entry(IFACE_ALL, UID_ALL, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0));
+                new NetworkStats.Entry(IFACE_ALL, UID_ALL, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0L));
     }
 
     /**
@@ -230,11 +253,11 @@
             final long fracTxPackets = entry.txPackets * overlap / duration;
             final int fracOperations = (int) (entry.operations * overlap / duration);
 
-            rxBytes[i] += fracRxBytes; entry.rxBytes -= fracRxBytes;
-            rxPackets[i] += fracRxPackets; entry.rxPackets -= fracRxPackets;
-            txBytes[i] += fracTxBytes; entry.txBytes -= fracTxBytes;
-            txPackets[i] += fracTxPackets; entry.txPackets -= fracTxPackets;
-            operations[i] += fracOperations; entry.operations -= fracOperations;
+            addLong(rxBytes, i, fracRxBytes); entry.rxBytes -= fracRxBytes;
+            addLong(rxPackets, i, fracRxPackets); entry.rxPackets -= fracRxPackets;
+            addLong(txBytes, i, fracTxBytes); entry.txBytes -= fracTxBytes;
+            addLong(txPackets, i, fracTxPackets); entry.txPackets -= fracTxPackets;
+            addLong(operations, i, fracOperations); entry.operations -= fracOperations;
 
             duration -= overlap;
         }
@@ -246,16 +269,16 @@
      */
     public void recordEntireHistory(NetworkStatsHistory input) {
         final NetworkStats.Entry entry = new NetworkStats.Entry(
-                IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0);
+                IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
         for (int i = 0; i < input.bucketCount; i++) {
             final long start = input.bucketStart[i];
             final long end = start + input.bucketDuration;
 
-            entry.rxBytes = input.rxBytes[i];
-            entry.rxPackets = input.rxPackets[i];
-            entry.txBytes = input.txBytes[i];
-            entry.txPackets = input.txPackets[i];
-            entry.operations = input.operations[i];
+            entry.rxBytes = getLong(input.rxBytes, i, 0L);
+            entry.rxPackets = getLong(input.rxPackets, i, 0L);
+            entry.txBytes = getLong(input.txBytes, i, 0L);
+            entry.txPackets = getLong(input.txPackets, i, 0L);
+            entry.operations = getLong(input.operations, i, 0L);
 
             recordData(start, end, entry);
         }
@@ -287,11 +310,11 @@
         if (bucketCount >= bucketStart.length) {
             final int newLength = Math.max(bucketStart.length, 10) * 3 / 2;
             bucketStart = Arrays.copyOf(bucketStart, newLength);
-            rxBytes = Arrays.copyOf(rxBytes, newLength);
-            rxPackets = Arrays.copyOf(rxPackets, newLength);
-            txBytes = Arrays.copyOf(txBytes, newLength);
-            txPackets = Arrays.copyOf(txPackets, newLength);
-            operations = Arrays.copyOf(operations, newLength);
+            if (rxBytes != null) rxBytes = Arrays.copyOf(rxBytes, newLength);
+            if (rxPackets != null) rxPackets = Arrays.copyOf(rxPackets, newLength);
+            if (txBytes != null) txBytes = Arrays.copyOf(txBytes, newLength);
+            if (txPackets != null) txPackets = Arrays.copyOf(txPackets, newLength);
+            if (operations != null) operations = Arrays.copyOf(operations, newLength);
         }
 
         // create gap when inserting bucket in middle
@@ -300,19 +323,19 @@
             final int length = bucketCount - index;
 
             System.arraycopy(bucketStart, index, bucketStart, dstPos, length);
-            System.arraycopy(rxBytes, index, rxBytes, dstPos, length);
-            System.arraycopy(rxPackets, index, rxPackets, dstPos, length);
-            System.arraycopy(txBytes, index, txBytes, dstPos, length);
-            System.arraycopy(txPackets, index, txPackets, dstPos, length);
-            System.arraycopy(operations, index, operations, dstPos, length);
+            if (rxBytes != null) System.arraycopy(rxBytes, index, rxBytes, dstPos, length);
+            if (rxPackets != null) System.arraycopy(rxPackets, index, rxPackets, dstPos, length);
+            if (txBytes != null) System.arraycopy(txBytes, index, txBytes, dstPos, length);
+            if (txPackets != null) System.arraycopy(txPackets, index, txPackets, dstPos, length);
+            if (operations != null) System.arraycopy(operations, index, operations, dstPos, length);
         }
 
         bucketStart[index] = start;
-        rxBytes[index] = 0;
-        rxPackets[index] = 0;
-        txBytes[index] = 0;
-        txPackets[index] = 0;
-        operations[index] = 0;
+        setLong(rxBytes, index, 0L);
+        setLong(rxPackets, index, 0L);
+        setLong(txBytes, index, 0L);
+        setLong(txPackets, index, 0L);
+        setLong(operations, index, 0L);
         bucketCount++;
     }
 
@@ -333,11 +356,11 @@
         if (i > 0) {
             final int length = bucketStart.length;
             bucketStart = Arrays.copyOfRange(bucketStart, i, length);
-            rxBytes = Arrays.copyOfRange(rxBytes, i, length);
-            rxPackets = Arrays.copyOfRange(rxPackets, i, length);
-            txBytes = Arrays.copyOfRange(txBytes, i, length);
-            txPackets = Arrays.copyOfRange(txPackets, i, length);
-            operations = Arrays.copyOfRange(operations, i, length);
+            if (rxBytes != null) rxBytes = Arrays.copyOfRange(rxBytes, i, length);
+            if (rxPackets != null) rxPackets = Arrays.copyOfRange(rxPackets, i, length);
+            if (txBytes != null) txBytes = Arrays.copyOfRange(txBytes, i, length);
+            if (txPackets != null) txPackets = Arrays.copyOfRange(txPackets, i, length);
+            if (operations != null) operations = Arrays.copyOfRange(operations, i, length);
             bucketCount -= i;
         }
     }
@@ -358,11 +381,11 @@
         final Entry entry = recycle != null ? recycle : new Entry();
         entry.bucketStart = start;
         entry.bucketDuration = end - start;
-        entry.rxBytes = 0;
-        entry.rxPackets = 0;
-        entry.txBytes = 0;
-        entry.txPackets = 0;
-        entry.operations = 0;
+        entry.rxBytes = rxBytes != null ? 0 : UNKNOWN;
+        entry.rxPackets = rxPackets != null ? 0 : UNKNOWN;
+        entry.txBytes = txBytes != null ? 0 : UNKNOWN;
+        entry.txPackets = txPackets != null ? 0 : UNKNOWN;
+        entry.operations = operations != null ? 0 : UNKNOWN;
 
         for (int i = bucketCount - 1; i >= 0; i--) {
             final long curStart = bucketStart[i];
@@ -380,11 +403,11 @@
             if (overlap <= 0) continue;
 
             // integer math each time is faster than floating point
-            entry.rxBytes += rxBytes[i] * overlap / bucketDuration;
-            entry.rxPackets += rxPackets[i] * overlap / bucketDuration;
-            entry.txBytes += txBytes[i] * overlap / bucketDuration;
-            entry.txPackets += txPackets[i] * overlap / bucketDuration;
-            entry.operations += operations[i] * overlap / bucketDuration;
+            if (rxBytes != null) entry.rxBytes += rxBytes[i] * overlap / bucketDuration;
+            if (rxPackets != null) entry.rxPackets += rxPackets[i] * overlap / bucketDuration;
+            if (txBytes != null) entry.txBytes += txBytes[i] * overlap / bucketDuration;
+            if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketDuration;
+            if (operations != null) entry.operations += operations[i] * overlap / bucketDuration;
         }
 
         return entry;
@@ -394,22 +417,31 @@
      * @deprecated only for temporary testing
      */
     @Deprecated
-    public void generateRandom(long start, long end, long rx, long tx) {
+    public void generateRandom(long start, long end, long rxBytes, long rxPackets, long txBytes,
+            long txPackets, long operations) {
         ensureBuckets(start, end);
 
         final NetworkStats.Entry entry = new NetworkStats.Entry(
-                IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0);
+                IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
         final Random r = new Random();
-        while (rx > 1024 && tx > 1024) {
+        while (rxBytes > 1024 && rxPackets > 128 && txBytes > 1024 && txPackets > 128
+                && operations > 32) {
             final long curStart = randomLong(r, start, end);
             final long curEnd = randomLong(r, curStart, end);
-            entry.rxBytes = randomLong(r, 0, rx);
-            entry.txBytes = randomLong(r, 0, tx);
+
+            entry.rxBytes = randomLong(r, 0, rxBytes);
+            entry.rxPackets = randomLong(r, 0, rxPackets);
+            entry.txBytes = randomLong(r, 0, txBytes);
+            entry.txPackets = randomLong(r, 0, txPackets);
+            entry.operations = randomLong(r, 0, operations);
+
+            rxBytes -= entry.rxBytes;
+            rxPackets -= entry.rxPackets;
+            txBytes -= entry.txBytes;
+            txPackets -= entry.txPackets;
+            operations -= entry.operations;
 
             recordData(curStart, curEnd, entry);
-
-            rx -= entry.rxBytes;
-            tx -= entry.txBytes;
         }
     }
 
@@ -430,11 +462,12 @@
         for (int i = start; i < bucketCount; i++) {
             pw.print(prefix);
             pw.print("  bucketStart="); pw.print(bucketStart[i]);
-            pw.print(" rxBytes="); pw.print(rxBytes[i]);
-            pw.print(" rxPackets="); pw.print(rxPackets[i]);
-            pw.print(" txBytes="); pw.print(txBytes[i]);
-            pw.print(" txPackets="); pw.print(txPackets[i]);
-            pw.print(" operations="); pw.println(operations[i]);
+            if (rxBytes != null) pw.print(" rxBytes="); pw.print(rxBytes[i]);
+            if (rxPackets != null) pw.print(" rxPackets="); pw.print(rxPackets[i]);
+            if (txBytes != null) pw.print(" txBytes="); pw.print(txBytes[i]);
+            if (txPackets != null) pw.print(" txPackets="); pw.print(txPackets[i]);
+            if (operations != null) pw.print(" operations="); pw.print(operations[i]);
+            pw.println();
         }
     }
 
@@ -455,12 +488,25 @@
         }
     };
 
+    private static long getLong(long[] array, int i, long value) {
+        return array != null ? array[i] : value;
+    }
+
+    private static void setLong(long[] array, int i, long value) {
+        if (array != null) array[i] = value;
+    }
+
+    private static void addLong(long[] array, int i, long value) {
+        if (array != null) array[i] += value;
+    }
+
     /**
      * Utility methods for interacting with {@link DataInputStream} and
      * {@link DataOutputStream}, mostly dealing with writing partial arrays.
      */
     public static class DataStreamUtils {
-        public static long[] readLongArray(DataInputStream in) throws IOException {
+        @Deprecated
+        public static long[] readFullLongArray(DataInputStream in) throws IOException {
             final int size = in.readInt();
             final long[] values = new long[size];
             for (int i = 0; i < values.length; i++) {
@@ -469,14 +515,59 @@
             return values;
         }
 
-        public static void writeLongArray(DataOutputStream out, long[] values, int size)
+        /**
+         * Read variable-length {@link Long} using protobuf-style approach.
+         */
+        public static long readVarLong(DataInputStream in) throws IOException {
+            int shift = 0;
+            long result = 0;
+            while (shift < 64) {
+                byte b = in.readByte();
+                result |= (long) (b & 0x7F) << shift;
+                if ((b & 0x80) == 0)
+                    return result;
+                shift += 7;
+            }
+            throw new ProtocolException("malformed long");
+        }
+
+        /**
+         * Write variable-length {@link Long} using protobuf-style approach.
+         */
+        public static void writeVarLong(DataOutputStream out, long value) throws IOException {
+            while (true) {
+                if ((value & ~0x7FL) == 0) {
+                    out.writeByte((int) value);
+                    return;
+                } else {
+                    out.writeByte(((int) value & 0x7F) | 0x80);
+                    value >>>= 7;
+                }
+            }
+        }
+
+        public static long[] readVarLongArray(DataInputStream in) throws IOException {
+            final int size = in.readInt();
+            if (size == -1) return null;
+            final long[] values = new long[size];
+            for (int i = 0; i < values.length; i++) {
+                values[i] = readVarLong(in);
+            }
+            return values;
+        }
+
+        public static void writeVarLongArray(DataOutputStream out, long[] values, int size)
                 throws IOException {
+            if (values == null) {
+                out.writeInt(-1);
+                return;
+            }
             if (size > values.length) {
                 throw new IllegalArgumentException("size larger than length");
             }
             out.writeInt(size);
             for (int i = 0; i < size; i++) {
-                out.writeLong(values[i]);
+                writeVarLong(out, values[i]);
             }
         }
     }
@@ -488,6 +579,7 @@
     public static class ParcelUtils {
         public static long[] readLongArray(Parcel in) {
             final int size = in.readInt();
+            if (size == -1) return null;
             final long[] values = new long[size];
             for (int i = 0; i < values.length; i++) {
                 values[i] = in.readLong();
@@ -496,6 +588,10 @@
         }
 
         public static void writeLongArray(Parcel out, long[] values, int size) {
+            if (values == null) {
+                out.writeInt(-1);
+                return;
+            }
             if (size > values.length) {
                 throw new IllegalArgumentException("size larger than length");
             }
@@ -504,25 +600,6 @@
                 out.writeLong(values[i]);
             }
         }
-
-        public static int[] readIntArray(Parcel in) {
-            final int size = in.readInt();
-            final int[] values = new int[size];
-            for (int i = 0; i < values.length; i++) {
-                values[i] = in.readInt();
-            }
-            return values;
-        }
-
-        public static void writeIntArray(Parcel out, int[] values, int size) {
-            if (size > values.length) {
-                throw new IllegalArgumentException("size larger than length");
-            }
-            out.writeInt(size);
-            for (int i = 0; i < size; i++) {
-                out.writeInt(values[i]);
-            }
-        }
     }
 
 }
diff --git a/core/java/android/net/VpnBuilder.java b/core/java/android/net/VpnBuilder.java
deleted file mode 100644
index 4582523..0000000
--- a/core/java/android/net/VpnBuilder.java
+++ /dev/null
@@ -1,413 +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 android.net;
-
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-
-import com.android.internal.net.VpnConfig;
-
-import java.net.InetAddress;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.DatagramSocket;
-import java.net.Socket;
-import java.util.ArrayList;
-
-/**
- * VpnBuilder is a framework which enables applications to build their
- * own VPN solutions. In general, it creates a virtual network interface,
- * configures addresses and routing rules, and returns a file descriptor
- * to the application. Each read from the descriptor retrieves an outgoing
- * packet which was routed to the interface. Each write to the descriptor
- * injects an incoming packet just like it was received from the interface.
- * The framework is running on Internet Protocol (IP), so packets are
- * always started with IP headers. The application then completes a VPN
- * connection by processing and exchanging packets with a remote server
- * over a secured tunnel.
- *
- * <p>Letting applications intercept packets raises huge security concerns.
- * Besides, a VPN application can easily break the network, and two of them
- * may conflict with each other. The framework takes several actions to
- * address these issues. Here are some key points:
- * <ul>
- *   <li>User action is required to create a VPN connection.</li>
- *   <li>There can be only one VPN connection running at the same time. The
- *       existing interface is deactivated when a new one is created.</li>
- *   <li>A system-managed notification is shown during the lifetime of a
- *       VPN connection.</li>
- *   <li>A system-managed dialog gives the information of the current VPN
- *       connection. It also provides a button to disconnect.</li>
- *   <li>The network is restored automatically when the file descriptor is
- *       closed. It also covers the cases when a VPN application is crashed
- *       or killed by the system.</li>
- * </ul>
- *
- * <p>There are two primary methods in this class: {@link #prepare} and
- * {@link #establish}. The former deals with the user action and stops
- * the existing VPN connection created by another application. The latter
- * creates a VPN interface using the parameters supplied to this builder.
- * An application must call {@link #prepare} to grant the right to create
- * an interface, and it can be revoked at any time by another application.
- * The application got revoked is notified by an {@link #ACTION_VPN_REVOKED}
- * broadcast. Here are the general steps to create a VPN connection:
- * <ol>
- *   <li>When the user press the button to connect, call {@link #prepare}
- *       and launch the intent if necessary.</li>
- *   <li>Register a receiver for {@link #ACTION_VPN_REVOKED} broadcasts.
- *   <li>Connect to the remote server and negotiate the network parameters
- *       of the VPN connection.</li>
- *   <li>Use those parameters to configure a VpnBuilder and create a VPN
- *       interface by calling {@link #establish}.</li>
- *   <li>Start processing packets between the returned file descriptor and
- *       the VPN tunnel.</li>
- *   <li>When an {@link #ACTION_VPN_REVOKED} broadcast is received, the
- *       interface is already deactivated by the framework. Close the file
- *       descriptor and shut down the VPN tunnel gracefully.
- * </ol>
- * Methods in this class can be used in activities and services. However,
- * the intent returned from {@link #prepare} must be launched from an
- * activity. The broadcast receiver can be registered at any time, but doing
- * it before calling {@link #establish} effectively avoids race conditions.
- *
- * <p class="note">Using this class requires
- * {@link android.Manifest.permission#VPN} permission.
- * @hide
- */
-public class VpnBuilder {
-
-    /**
-     * Broadcast intent action indicating that the VPN application has been
-     * revoked. This can be only received by the target application on the
-     * receiver explicitly registered using {@link Context#registerReceiver}.
-     *
-     * <p>This is a protected intent that can only be sent by the system.
-     */
-    public static final String ACTION_VPN_REVOKED = VpnConfig.ACTION_VPN_REVOKED;
-
-    /**
-     * Use IConnectivityManager instead since those methods are hidden and
-     * not available in ConnectivityManager.
-     */
-    private static IConnectivityManager getService() {
-        return IConnectivityManager.Stub.asInterface(
-                ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
-    }
-
-    /**
-     * Prepare to establish a VPN connection. This method returns {@code null}
-     * if the VPN application is already prepared. Otherwise, it returns an
-     * {@link Intent} to a system activity. The application should launch the
-     * activity using {@link Activity#startActivityForResult} to get itself
-     * prepared. The activity may pop up a dialog to require user action, and
-     * the result will come back to the application through its
-     * {@link Activity#onActivityResult}. The application becomes prepared if
-     * the result is {@link Activity#RESULT_OK}, and it is granted to create a
-     * VPN interface by calling {@link #establish}.
-     *
-     * <p>Only one application can be granted at the same time. The right
-     * is revoked when another application is granted. The application
-     * losing the right will be notified by an {@link #ACTION_VPN_REVOKED}
-     * broadcast, and its VPN interface will be deactivated by the system.
-     * The application should then notify the remote server and disconnect
-     * gracefully. Unless the application becomes prepared again, subsequent
-     * calls to {@link #establish} will return {@code null}.
-     *
-     * @see #establish
-     * @see #ACTION_VPN_REVOKED
-     */
-    public static Intent prepare(Context context) {
-        try {
-            if (getService().prepareVpn(context.getPackageName(), null)) {
-                return null;
-            }
-        } catch (RemoteException e) {
-            // ignore
-        }
-        return VpnConfig.getIntentForConfirmation();
-    }
-
-    private VpnConfig mConfig = new VpnConfig();
-    private StringBuilder mAddresses = new StringBuilder();
-    private StringBuilder mRoutes = new StringBuilder();
-
-    /**
-     * Set the name of this session. It will be displayed in system-managed
-     * dialogs and notifications. This is recommended not required.
-     */
-    public VpnBuilder setSession(String session) {
-        mConfig.session = session;
-        return this;
-    }
-
-    /**
-     * Set the {@link PendingIntent} to an activity for users to configure
-     * the VPN connection. If it is not set, the button to configure will
-     * not be shown in system-managed dialogs.
-     */
-    public VpnBuilder setConfigureIntent(PendingIntent intent) {
-        mConfig.configureIntent = intent;
-        return this;
-    }
-
-    /**
-     * Set the maximum transmission unit (MTU) of the VPN interface. If it
-     * is not set, the default value in the operating system will be used.
-     *
-     * @throws IllegalArgumentException if the value is not positive.
-     */
-    public VpnBuilder setMtu(int mtu) {
-        if (mtu <= 0) {
-            throw new IllegalArgumentException("Bad mtu");
-        }
-        mConfig.mtu = mtu;
-        return this;
-    }
-
-    /**
-     * Private method to validate address and prefixLength.
-     */
-    private static void check(InetAddress address, int prefixLength) {
-        if (address.isLoopbackAddress()) {
-            throw new IllegalArgumentException("Bad address");
-        }
-        if (address instanceof Inet4Address) {
-            if (prefixLength < 0 || prefixLength > 32) {
-                throw new IllegalArgumentException("Bad prefixLength");
-            }
-        } else if (address instanceof Inet6Address) {
-            if (prefixLength < 0 || prefixLength > 128) {
-                throw new IllegalArgumentException("Bad prefixLength");
-            }
-        } else {
-            throw new IllegalArgumentException("Unsupported family");
-        }
-    }
-
-    /**
-     * Convenience method to add a network address to the VPN interface
-     * using a numeric address string. See {@link InetAddress} for the
-     * definitions of numeric address formats.
-     *
-     * @throws IllegalArgumentException if the address is invalid.
-     * @see #addAddress(InetAddress, int)
-     */
-    public VpnBuilder addAddress(String address, int prefixLength) {
-        return addAddress(InetAddress.parseNumericAddress(address), prefixLength);
-    }
-
-    /**
-     * Add a network address to the VPN interface. Both IPv4 and IPv6
-     * addresses are supported. At least one address must be set before
-     * calling {@link #establish}.
-     *
-     * @throws IllegalArgumentException if the address is invalid.
-     */
-    public VpnBuilder addAddress(InetAddress address, int prefixLength) {
-        check(address, prefixLength);
-
-        if (address.isAnyLocalAddress()) {
-            throw new IllegalArgumentException("Bad address");
-        }
-
-        mAddresses.append(String.format(" %s/%d", address.getHostAddress(), prefixLength));
-        return this;
-    }
-
-    /**
-     * Convenience method to add a network route to the VPN interface
-     * using a numeric address string. See {@link InetAddress} for the
-     * definitions of numeric address formats.
-     *
-     * @see #addRoute(InetAddress, int)
-     * @throws IllegalArgumentException if the route is invalid.
-     */
-    public VpnBuilder addRoute(String address, int prefixLength) {
-        return addRoute(InetAddress.parseNumericAddress(address), prefixLength);
-    }
-
-    /**
-     * Add a network route to the VPN interface. Both IPv4 and IPv6
-     * routes are supported.
-     *
-     * @throws IllegalArgumentException if the route is invalid.
-     */
-    public VpnBuilder addRoute(InetAddress address, int prefixLength) {
-        check(address, prefixLength);
-
-        int offset = prefixLength / 8;
-        byte[] bytes = address.getAddress();
-        if (offset < bytes.length) {
-            if ((byte)(bytes[offset] << (prefixLength % 8)) != 0) {
-                throw new IllegalArgumentException("Bad address");
-            }
-            while (++offset < bytes.length) {
-                if (bytes[offset] != 0) {
-                    throw new IllegalArgumentException("Bad address");
-                }
-            }
-        }
-
-        mRoutes.append(String.format(" %s/%d", address.getHostAddress(), prefixLength));
-        return this;
-    }
-
-    /**
-     * Convenience method to add a DNS server to the VPN connection
-     * using a numeric address string. See {@link InetAddress} for the
-     * definitions of numeric address formats.
-     *
-     * @throws IllegalArgumentException if the address is invalid.
-     * @see #addDnsServer(InetAddress)
-     */
-    public VpnBuilder addDnsServer(String address) {
-        return addDnsServer(InetAddress.parseNumericAddress(address));
-    }
-
-    /**
-     * Add a DNS server to the VPN connection. Both IPv4 and IPv6
-     * addresses are supported. If none is set, the DNS servers of
-     * the default network will be used.
-     *
-     * @throws IllegalArgumentException if the address is invalid.
-     */
-    public VpnBuilder addDnsServer(InetAddress address) {
-        if (address.isLoopbackAddress() || address.isAnyLocalAddress()) {
-            throw new IllegalArgumentException("Bad address");
-        }
-        if (mConfig.dnsServers == null) {
-            mConfig.dnsServers = new ArrayList<String>();
-        }
-        mConfig.dnsServers.add(address.getHostAddress());
-        return this;
-    }
-
-    /**
-     * Add a search domain to the DNS resolver.
-     */
-    public VpnBuilder addSearchDomain(String domain) {
-        if (mConfig.searchDomains == null) {
-            mConfig.searchDomains = new ArrayList<String>();
-        }
-        mConfig.searchDomains.add(domain);
-        return this;
-    }
-
-    /**
-     * Create a VPN interface using the parameters supplied to this builder.
-     * The interface works on IP packets, and a file descriptor is returned
-     * for the application to access them. Each read retrieves an outgoing
-     * packet which was routed to the interface. Each write injects an
-     * incoming packet just like it was received from the interface. The file
-     * descriptor is put into non-blocking mode by default to avoid blocking
-     * Java threads. To use the file descriptor completely in native space,
-     * see {@link ParcelFileDescriptor#detachFd()}. The application MUST
-     * close the file descriptor when the VPN connection is terminated. The
-     * VPN interface will be removed and the network will be restored by the
-     * framework automatically.
-     *
-     * <p>To avoid conflicts, there can be only one active VPN interface at
-     * the same time. Usually network parameters are never changed during the
-     * lifetime of a VPN connection. It is also common for an application to
-     * create a new file descriptor after closing the previous one. However,
-     * it is rare but not impossible to have two interfaces while performing a
-     * seamless handover. In this case, the old interface will be deactivated
-     * when the new one is configured successfully. Both file descriptors are
-     * valid but now outgoing packets will be routed to the new interface.
-     * Therefore, after draining the old file descriptor, the application MUST
-     * close it and start using the new file descriptor. If the new interface
-     * cannot be created, the existing interface and its file descriptor remain
-     * untouched.
-     *
-     * <p>An exception will be thrown if the interface cannot be created for
-     * any reason. However, this method returns {@code null} if the application
-     * is not prepared or is revoked by another application. This helps solve
-     * possible race conditions while handling {@link #ACTION_VPN_REVOKED}
-     * broadcasts.
-     *
-     * @return {@link ParcelFileDescriptor} of the VPN interface, or
-     *         {@code null} if the application is not prepared.
-     * @throws IllegalArgumentException if a parameter is not accepted by the
-     *         operating system.
-     * @throws IllegalStateException if a parameter cannot be applied by the
-     *         operating system.
-     * @see #prepare
-     */
-    public ParcelFileDescriptor establish() {
-        mConfig.addresses = mAddresses.toString();
-        mConfig.routes = mRoutes.toString();
-
-        try {
-            return getService().establishVpn(mConfig);
-        } catch (RemoteException e) {
-            throw new IllegalStateException(e);
-        }
-    }
-
-    /**
-     * Protect a socket from VPN connections. The socket will be bound to the
-     * current default network interface, so its traffic will not be forwarded
-     * through VPN. This method is useful if some connections need to be kept
-     * outside of VPN. For example, a VPN tunnel should protect itself if its
-     * destination is covered by VPN routes. Otherwise its outgoing packets
-     * will be sent back to the VPN interface and cause an infinite loop.
-     *
-     * <p>The socket is NOT closed by this method.
-     *
-     * @return {@code true} on success.
-     */
-    public static boolean protect(int socket) {
-        ParcelFileDescriptor dup = null;
-        try {
-            dup = ParcelFileDescriptor.fromFd(socket);
-            return getService().protectVpn(dup);
-        } catch (Exception e) {
-            return false;
-        } finally {
-            try {
-                dup.close();
-            } catch (Exception e) {
-                // ignore
-            }
-        }
-    }
-
-    /**
-     * Protect a {@link Socket} from VPN connections.
-     *
-     * @return {@code true} on success.
-     * @see #protect(int)
-     */
-    public static boolean protect(Socket socket) {
-        return protect(socket.getFileDescriptor$().getInt$());
-    }
-
-    /**
-     * Protect a {@link DatagramSocket} from VPN connections.
-     *
-     * @return {@code true} on success.
-     * @see #protect(int)
-     */
-    public static boolean protect(DatagramSocket socket) {
-        return protect(socket.getFileDescriptor$().getInt$());
-    }
-}
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index b668f30..6ba3451 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -21,6 +21,7 @@
 import android.os.Parcelable;
 
 import java.lang.UnsupportedOperationException;
+import java.nio.charset.Charset;
 import java.nio.charset.Charsets;
 import java.util.Arrays;
 
@@ -139,6 +140,22 @@
      */
     public static final byte[] RTD_HANDOVER_SELECT = {0x48, 0x73}; // "Hs"
 
+    /**
+     * RTD Android app type. For use with TNF_EXTERNAL.
+     * <p>
+     * The payload of a record with type RTD_ANDROID_APP
+     * should be the package name identifying an application.
+     * Multiple RTD_ANDROID_APP records may be included
+     * in a single {@link NdefMessage}.
+     * <p>
+     * Use {@link #createApplicationRecord(String)} to create
+     * RTD_ANDROID_APP records.
+     * @hide
+     */
+    // TODO unhide for ICS
+    // TODO recheck docs
+    public static final byte[] RTD_ANDROID_APP = "android.com:pkg".getBytes();
+
     private static final byte FLAG_MB = (byte) 0x80;
     private static final byte FLAG_ME = (byte) 0x40;
     private static final byte FLAG_CF = (byte) 0x20;
@@ -333,6 +350,29 @@
     }
 
     /**
+     * Creates an Android application NDEF record.
+     * <p>
+     * When an Android device dispatches an {@link NdefMessage}
+     * containing one or more Android application records,
+     * the applications contained in those records will be the
+     * preferred target for the NDEF_DISCOVERED intent, in
+     * the order in which they appear in the {@link NdefMessage}.
+     * <p>
+     * If none of the applications are installed on the device,
+     * a Market link will be opened to the first application.
+     * <p>
+     * Note that Android application records do not overrule
+     * applications that have called {@link NfcAdapter#enableForegroundDispatch}.
+     * @hide
+     */
+    // TODO unhide for ICS
+    // TODO recheck javadoc - should mention this works from ICS only
+    public static NdefRecord createApplicationRecord(String packageName) {
+        return new NdefRecord(TNF_EXTERNAL_TYPE, RTD_ANDROID_APP, new byte[] {},
+                packageName.getBytes(Charsets.US_ASCII));
+    }
+
+    /**
      * Creates an NDEF record of well known type URI.
      */
     public static NdefRecord createUri(Uri uri) {
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index da2afb6..20a731e 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -818,6 +818,18 @@
     public static native void getMemoryInfo(int pid, MemoryInfo memoryInfo);
 
     /**
+     * Retrieves the PSS memory used by the process as given by the
+     * smaps.
+     */
+    public static native long getPss();
+
+    /**
+     * Retrieves the PSS memory used by the process as given by the
+     * smaps. @hide
+     */
+    public static native long getPss(int pid);
+
+    /**
      * Establish an object allocation limit in the current thread.
      * This feature was never enabled in release builds.  The
      * allocation limits feature was removed in Honeycomb.  This
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 3704248..bc4e00c 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -240,6 +240,11 @@
     void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces);
 
     /**
+     * Return status of bandwidth control module.
+     */
+    boolean isBandwidthControlEnabled();
+
+    /**
      * Configures bandwidth throttling on an interface.
      */
     void setInterfaceThrottle(String iface, int rxKbps, int txKbps);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a6c3387..1ecdfce 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3042,7 +3042,7 @@
 
         /**
          * Boolean to determine whether to notify on disabling a network.  Secure setting used
-         * to notify user only once.  This setting is not monitored continuously.
+         * to notify user only once.
          * @hide
          */
         public static final String WIFI_WATCHDOG_SHOW_DISABLED_NETWORK_POPUP =
@@ -3166,6 +3166,18 @@
         public static final String TTY_MODE_ENABLED = "tty_mode_enabled";
 
         /**
+         * The number of milliseconds to delay before sending out Connectivyt Change broadcasts
+         * @hide
+         */
+        public static final String CONNECTIVITY_CHANGE_DELAY = "connectivity_change_delay";
+
+        /**
+         * Default value for CONNECTIVITY_CHANGE_DELAY in milliseconds.
+         * @hide
+         */
+        public static final int CONNECTIVITY_CHANGE_DELAY_DEFAULT = 3000;
+
+        /**
          * Controls whether settings backup is enabled.
          * Type: int ( 0 = disabled, 1 = enabled )
          * @hide
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 5217624..814f50b 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -41,7 +41,7 @@
  * </ul>
  *
  * <P> The minimum permission needed to access this content provider is
- * {@link Manifest.permission#READ_WRITE_OWN_VOICEMAIL}
+ * {@link Manifest.permission#ADD_VOICEMAIL}
  *
  * <P>Voicemails are inserted by what is called as a "voicemail source"
  * application, which is responsible for syncing voicemail data between a remote
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index f498bb2..8c04853 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -194,7 +194,7 @@
     }
 
     private synchronized void onBluetoothEnable() {
-        String devices = mBluetoothService.getProperty("Devices");
+        String devices = mBluetoothService.getProperty("Devices", true);
         if (devices != null) {
             String [] paths = devices.split(",");
             for (String path: paths) {
diff --git a/core/java/android/server/BluetoothAdapterStateMachine.java b/core/java/android/server/BluetoothAdapterStateMachine.java
index cb18ade..031375e 100644
--- a/core/java/android/server/BluetoothAdapterStateMachine.java
+++ b/core/java/android/server/BluetoothAdapterStateMachine.java
@@ -39,7 +39,7 @@
  *                         (BluetootOn)<----------------------<-
  *                           |    ^    -------------------->-  |
  *                           |    |                         |  |
- *                 TURN_OFF  |    | BECAME_PAIRABLE     m1 |  | USER_TURN_ON
+ *                 TURN_OFF  |    | BECAME_PAIRABLE      m1 |  | USER_TURN_ON
  *         AIRPLANE_MODE_ON  |    |                         |  |
  *                           V    |                         |  |
  *                         (Switching)                   (PerProcessState)
@@ -47,7 +47,7 @@
  *     BECAME_NON_PAIRABLE&  |    | TURN_ON(_CONTINUE)      |  |
  * ALL_DEVICES_DISCONNECTED  |    |                     m2  |  |
  *                           V    |------------------------<   | BECAME_PAIRABLE
- *                          (HotOff)---------------------------- PER_PROCESS_TURN_ON
+ *                          (HotOff)-------------------------->- PER_PROCESS_TURN_ON
  *                           /    ^
  *                          /     |  SERVICE_RECORD_LOADED
  *                         |      |
@@ -59,7 +59,7 @@
  *                           (PowerOff)   <----- initial state
  *
  * Legend:
- * m1 = USER_TURN_OFF
+ * m1 = TURN_HOT
  * m2 = Transition to HotOff when number of process wanting BT on is 0.
  *      BECAME_NON_PAIRABLE will make the transition.
  */
@@ -73,6 +73,9 @@
     static final int USER_TURN_ON = 1;
     // We get this message when user tries to turn off BT
     static final int USER_TURN_OFF = 2;
+    // Per process enable / disable messages
+    static final int PER_PROCESS_TURN_ON = 3;
+    static final int PER_PROCESS_TURN_OFF = 4;
 
     // Message(what) to report a event that the state machine need to respond to
     //
@@ -102,9 +105,8 @@
     private static final int TURN_ON_CONTINUE = 102;
     // Unload firmware, turning off Bluetooth module power
     private static final int TURN_COLD = 103;
-    // Per process enable / disable messages
-    static final int PER_PROCESS_TURN_ON = 104;
-    static final int PER_PROCESS_TURN_OFF = 105;
+    // Device disconnecting timeout happens
+    private static final int DEVICES_DISCONNECT_TIMEOUT = 104;
 
     private Context mContext;
     private BluetoothService mBluetoothService;
@@ -120,6 +122,9 @@
     // this is the BluetoothAdapter state that reported externally
     private int mPublicState;
 
+    // timeout value waiting for all the devices to be disconnected
+    private static final int DEVICES_DISCONNECT_TIMEOUT_TIME = 3000;
+
     BluetoothAdapterStateMachine(Context context, BluetoothService bluetoothService,
                                  BluetoothAdapter bluetoothAdapter) {
         super(TAG);
@@ -214,8 +219,9 @@
                 case PER_PROCESS_TURN_OFF:
                     perProcessCallback(false, (IBluetoothStateChangeCallback) message.obj);
                     break;
-                case AIRPLANE_MODE_ON:
-                case USER_TURN_OFF: // ignore
+                case USER_TURN_OFF:
+                    Log.w(TAG, "PowerOff received: " + message.what);
+                case AIRPLANE_MODE_ON: // ignore
                     break;
                 default:
                     return NOT_HANDLED;
@@ -301,7 +307,8 @@
                 case PER_PROCESS_TURN_OFF:
                     deferMessage(message);
                     break;
-                case USER_TURN_OFF: // ignore
+                case USER_TURN_OFF:
+                    Log.w(TAG, "WarmUp received: " + message.what);
                     break;
                 default:
                     return NOT_HANDLED;
@@ -344,7 +351,6 @@
                     mBluetoothService.shutoffBluetooth();
                     mEventLoop.stop();
                     transitionTo(mPowerOff);
-                    // ASSERT no support of config_bluetooth_adapter_quick_switch
                     broadcastState(BluetoothAdapter.STATE_OFF);
                     break;
                 case AIRPLANE_MODE_OFF:
@@ -354,8 +360,6 @@
                         broadcastState(BluetoothAdapter.STATE_TURNING_ON);
                     }
                     break;
-                case USER_TURN_OFF: // ignore
-                    break;
                 case PER_PROCESS_TURN_ON:
                     transitionTo(mPerProcessState);
 
@@ -368,6 +372,8 @@
                 case PER_PROCESS_TURN_OFF:
                     perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj);
                     break;
+                case USER_TURN_OFF: // ignore
+                    break;
                 default:
                     return NOT_HANDLED;
             }
@@ -399,16 +405,28 @@
                 case BECAME_NON_PAIRABLE:
                     if (mBluetoothService.getAdapterConnectionState() ==
                         BluetoothAdapter.STATE_DISCONNECTED) {
+                        removeMessages(DEVICES_DISCONNECT_TIMEOUT);
                         transitionTo(mHotOff);
                         finishSwitchingOff();
                     }
                     break;
                 case ALL_DEVICES_DISCONNECTED:
+                    removeMessages(DEVICES_DISCONNECT_TIMEOUT);
                     if (mBluetoothService.getScanMode() == BluetoothAdapter.SCAN_MODE_NONE) {
                         transitionTo(mHotOff);
                         finishSwitchingOff();
                     }
                     break;
+                case DEVICES_DISCONNECT_TIMEOUT:
+                    sendMessage(ALL_DEVICES_DISCONNECTED);
+                    // reset the hardware for error recovery
+                    Log.e(TAG, "Devices failed to disconnect, reseting...");
+                    deferMessage(obtainMessage(TURN_COLD));
+                    if (mContext.getResources().getBoolean
+                        (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
+                        deferMessage(obtainMessage(TURN_HOT));
+                    }
+                    break;
                 case USER_TURN_ON:
                 case AIRPLANE_MODE_OFF:
                 case AIRPLANE_MODE_ON:
@@ -457,7 +475,7 @@
                     }
                     if (!mBluetoothService.isApplicationStateChangeTrackerEmpty()) {
                         transitionTo(mPerProcessState);
-                        deferMessage(obtainMessage(USER_TURN_OFF));
+                        deferMessage(obtainMessage(TURN_HOT));
                         break;
                     }
                     //$FALL-THROUGH$ to AIRPLANE_MODE_ON
@@ -466,6 +484,7 @@
                     broadcastState(BluetoothAdapter.STATE_TURNING_OFF);
                     mBluetoothService.switchConnectable(false);
                     mBluetoothService.disconnectDevices();
+                    sendMessageDelayed(DEVICES_DISCONNECT_TIMEOUT, DEVICES_DISCONNECT_TIMEOUT_TIME);
 
                     // we turn all the way to PowerOff with AIRPLANE_MODE_ON
                     if (message.what == AIRPLANE_MODE_ON) {
@@ -474,8 +493,9 @@
                         deferMessage(obtainMessage(AIRPLANE_MODE_ON));
                     }
                     break;
-                case AIRPLANE_MODE_OFF: // ignore
-                case USER_TURN_ON: // ignore
+                case AIRPLANE_MODE_OFF:
+                case USER_TURN_ON:
+                    Log.w(TAG, "BluetoothOn received: " + message.what);
                     break;
                 case PER_PROCESS_TURN_ON:
                     perProcessCallback(true, (IBluetoothStateChangeCallback)message.obj);
@@ -526,19 +546,34 @@
                     // run bluetooth now that it's turned on
                     mBluetoothService.runBluetooth();
                     break;
-               case USER_TURN_OFF:
+                case TURN_HOT:
                     broadcastState(BluetoothAdapter.STATE_TURNING_OFF);
                     if (mBluetoothService.getAdapterConnectionState() !=
                         BluetoothAdapter.STATE_DISCONNECTED) {
                         mBluetoothService.disconnectDevices();
+                        sendMessageDelayed(DEVICES_DISCONNECT_TIMEOUT,
+                                           DEVICES_DISCONNECT_TIMEOUT_TIME);
                         break;
                     }
                     //$FALL-THROUGH$ all devices are already disconnected
                 case ALL_DEVICES_DISCONNECTED:
+                    removeMessages(DEVICES_DISCONNECT_TIMEOUT);
                     mBluetoothService.finishDisable();
                     broadcastState(BluetoothAdapter.STATE_OFF);
                     break;
-               case PER_PROCESS_TURN_OFF:
+                case DEVICES_DISCONNECT_TIMEOUT:
+                    mBluetoothService.finishDisable();
+                    broadcastState(BluetoothAdapter.STATE_OFF);
+                    Log.e(TAG, "Devices fail to disconnect, reseting...");
+                    transitionTo(mHotOff);
+                    deferMessage(obtainMessage(TURN_COLD));
+                    for (IBluetoothStateChangeCallback c:
+                             mBluetoothService.getApplicationStateChangeCallbacks()) {
+                        perProcessCallback(false, c);
+                        deferMessage(obtainMessage(PER_PROCESS_TURN_ON, c));
+                    }
+                    break;
+                case PER_PROCESS_TURN_OFF:
                     perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj);
                     if (mBluetoothService.isApplicationStateChangeTrackerEmpty()) {
                         mBluetoothService.switchConnectable(false);
@@ -557,6 +592,9 @@
                     // we turn all the way to PowerOff with AIRPLANE_MODE_ON
                     deferMessage(obtainMessage(AIRPLANE_MODE_ON));
                     break;
+                case USER_TURN_OFF:
+                    Log.w(TAG, "PerProcessState received: " + message.what);
+                    break;
                 default:
                     return NOT_HANDLED;
             }
diff --git a/core/java/android/server/BluetoothPanProfileHandler.java b/core/java/android/server/BluetoothPanProfileHandler.java
index 0d63e19..37cfdc4 100644
--- a/core/java/android/server/BluetoothPanProfileHandler.java
+++ b/core/java/android/server/BluetoothPanProfileHandler.java
@@ -145,13 +145,14 @@
             return false;
         }
 
-        handlePanDeviceStateChange(device, BluetoothPan.STATE_CONNECTING,
+        // Send interface as null as it is not known
+        handlePanDeviceStateChange(device, null, BluetoothPan.STATE_CONNECTING,
                                            BluetoothPan.LOCAL_PANU_ROLE);
         if (mBluetoothService.connectPanDeviceNative(objectPath, "nap")) {
             debugLog("connecting to PAN");
             return true;
         } else {
-            handlePanDeviceStateChange(device, BluetoothPan.STATE_DISCONNECTED,
+            handlePanDeviceStateChange(device, null, BluetoothPan.STATE_DISCONNECTED,
                                                 BluetoothPan.LOCAL_PANU_ROLE);
             errorLog("could not connect to PAN");
             return false;
@@ -168,16 +169,16 @@
                     panDevice.mLocalRole == BluetoothPan.LOCAL_NAP_ROLE) {
                 String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
 
-                handlePanDeviceStateChange(device, BluetoothPan.STATE_DISCONNECTING,
-                        panDevice.mLocalRole);
+                handlePanDeviceStateChange(device, panDevice.mIface,
+                        BluetoothPan.STATE_DISCONNECTING, panDevice.mLocalRole);
 
                 if (!mBluetoothService.disconnectPanServerDeviceNative(objectPath,
                         device.getAddress(),
-                        panDevice.mIfaceAddr)) {
+                        panDevice.mIface)) {
                     errorLog("could not disconnect Pan Server Device "+device.getAddress());
 
                     // Restore prev state
-                    handlePanDeviceStateChange(device, state,
+                    handlePanDeviceStateChange(device, panDevice.mIface, state,
                             panDevice.mLocalRole);
 
                     return false;
@@ -230,19 +231,19 @@
             return false;
         }
 
-        handlePanDeviceStateChange(device, BluetoothPan.STATE_DISCONNECTING,
+        handlePanDeviceStateChange(device, panDevice.mIface, BluetoothPan.STATE_DISCONNECTING,
                                     panDevice.mLocalRole);
         if (panDevice.mLocalRole == BluetoothPan.LOCAL_NAP_ROLE) {
             if (!mBluetoothService.disconnectPanServerDeviceNative(objectPath, device.getAddress(),
                     panDevice.mIface)) {
                 // Restore prev state, this shouldn't happen
-                handlePanDeviceStateChange(device, state, panDevice.mLocalRole);
+                handlePanDeviceStateChange(device, panDevice.mIface, state, panDevice.mLocalRole);
                 return false;
             }
         } else {
             if (!mBluetoothService.disconnectPanDeviceNative(objectPath)) {
                 // Restore prev state, this shouldn't happen
-                handlePanDeviceStateChange(device, state, panDevice.mLocalRole);
+                handlePanDeviceStateChange(device, panDevice.mIface, state, panDevice.mLocalRole);
                 return false;
             }
         }
@@ -291,6 +292,7 @@
             panDevice.mState = state;
             panDevice.mIfaceAddr = ifaceAddr;
             panDevice.mLocalRole = role;
+            panDevice.mIface = iface;
         }
 
         Intent intent = new Intent(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
@@ -304,11 +306,6 @@
         mBluetoothService.sendConnectionStateChange(device, state, prevState);
     }
 
-    void handlePanDeviceStateChange(BluetoothDevice device,
-                                                 int state, int role) {
-        handlePanDeviceStateChange(device, null, state, role);
-    }
-
     private class BluetoothPanDevice {
         private int mState;
         private String mIfaceAddr;
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 28546dc..0357958 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -798,8 +798,15 @@
         return true;
     }
 
-    /*package*/ synchronized String getProperty(String name) {
-        if (!isEnabledInternal()) return null;
+    /*package*/ synchronized String getProperty(String name, boolean checkState) {
+        // If checkState is false, check if the event loop is running.
+        // before making the call to Bluez
+        if (checkState) {
+            if (!isEnabledInternal()) return null;
+        } else if (!mEventLoop.isEventLoopRunning()) {
+            return null;
+        }
+
         return mAdapterProperties.getProperty(name);
     }
 
@@ -825,17 +832,19 @@
 
     public synchronized String getAddress() {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        return getProperty("Address");
+        // Don't check state since we want to provide address, even if BT is off
+        return getProperty("Address", false);
     }
 
     public synchronized String getName() {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        return getProperty("Name");
+        // Don't check state since we want to provide name, even if BT is off
+        return getProperty("Name", false);
     }
 
     public synchronized ParcelUuid[] getUuids() {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        String value =  getProperty("UUIDs");
+        String value =  getProperty("UUIDs", true);
         if (value == null) return null;
         return convertStringToParcelUuid(value);
     }
@@ -915,7 +924,7 @@
      */
     public synchronized int getDiscoverableTimeout() {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        String timeout = getProperty("DiscoverableTimeout");
+        String timeout = getProperty("DiscoverableTimeout", true);
         if (timeout != null)
            return Integer.valueOf(timeout);
         else
@@ -927,8 +936,8 @@
         if (!isEnabledInternal())
             return BluetoothAdapter.SCAN_MODE_NONE;
 
-        boolean pairable = getProperty("Pairable").equals("true");
-        boolean discoverable = getProperty("Discoverable").equals("true");
+        boolean pairable = getProperty("Pairable", true).equals("true");
+        boolean discoverable = getProperty("Discoverable", true).equals("true");
         return bluezStringToScanMode (pairable, discoverable);
     }
 
@@ -951,7 +960,7 @@
     public synchronized boolean isDiscovering() {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
 
-        String discoveringProperty = mAdapterProperties.getProperty("Discovering");
+        String discoveringProperty = getProperty("Discovering", false);
         if (discoveringProperty == null) {
             return false;
         }
@@ -1565,6 +1574,8 @@
     @Override
     public boolean changeApplicationBluetoothState(boolean on,
             IBluetoothStateChangeCallback callback, IBinder binder) {
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+
         int pid = Binder.getCallingPid();
         //mStateChangeTracker is a synchronized map
         if (!mStateChangeTracker.containsKey(pid)) {
@@ -2339,7 +2350,7 @@
 
     synchronized String[] getKnownDevices() {
         String[] bonds = null;
-        String val = getProperty("Devices");
+        String val = getProperty("Devices", true);
         if (val != null) {
             bonds = val.split(",");
         }
@@ -2348,7 +2359,7 @@
 
     private void initProfileState() {
         String[] bonds = null;
-        String val = mAdapterProperties.getProperty("Devices");
+        String val = getProperty("Devices", false);
         if (val != null) {
             bonds = val.split(",");
         }
diff --git a/core/java/android/service/textservice/SpellCheckerService.java b/core/java/android/service/textservice/SpellCheckerService.java
index 6f70ab8..3e2e38e 100644
--- a/core/java/android/service/textservice/SpellCheckerService.java
+++ b/core/java/android/service/textservice/SpellCheckerService.java
@@ -22,6 +22,7 @@
 
 import android.app.Service;
 import android.content.Intent;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
@@ -43,45 +44,6 @@
 
     private final SpellCheckerServiceBinder mBinder = new SpellCheckerServiceBinder(this);
 
-    /**
-     * Get suggestions for specified text in TextInfo.
-     * This function will run on the incoming IPC thread. So, this is not called on the main thread,
-     * but will be called in series on another thread.
-     * @param textInfo the text metadata
-     * @param suggestionsLimit the number of limit of suggestions returned
-     * @param locale the locale for getting suggestions
-     * @return SuggestionInfo which contains suggestions for textInfo
-     */
-    public abstract SuggestionsInfo getSuggestions(
-            TextInfo textInfo, int suggestionsLimit, String locale);
-
-    /**
-     * A batch process of onGetSuggestions.
-     * This function will run on the incoming IPC thread. So, this is not called on the main thread,
-     * but will be called in series on another thread.
-     * @param textInfos an array of the text metadata
-     * @param locale the locale for getting suggestions
-     * @param suggestionsLimit the number of limit of suggestions returned
-     * @param sequentialWords true if textInfos can be treated as sequential words.
-     * @return an array of SuggestionInfo of onGetSuggestions
-     */
-    public SuggestionsInfo[] getSuggestionsMultiple(
-            TextInfo[] textInfos, String locale, int suggestionsLimit, boolean sequentialWords) {
-        final int length = textInfos.length;
-        final SuggestionsInfo[] retval = new SuggestionsInfo[length];
-        for (int i = 0; i < length; ++i) {
-            retval[i] = getSuggestions(textInfos[i], suggestionsLimit, locale);
-            retval[i].setCookieAndSequence(textInfos[i].getCookie(), textInfos[i].getSequence());
-        }
-        return retval;
-    }
-
-    /**
-     * Request to abort all tasks executed in SpellChecker.
-     * This function will run on the incoming IPC thread. So, this is not called on the main thread,
-     * but will be called in series on another thread.
-     */
-    public void cancel() {}
 
     /**
      * Implement to return the implementation of the internal spell checker
@@ -95,36 +57,125 @@
         return mBinder;
     }
 
-    private static class SpellCheckerSessionImpl extends ISpellCheckerSession.Stub {
-        private final WeakReference<SpellCheckerService> mInternalServiceRef;
-        private final String mLocale;
-        private final ISpellCheckerSessionListener mListener;
+    /**
+     * Factory method to create a spell checker session impl
+     * @return SpellCheckerSessionImpl which should be overridden by a concrete implementation.
+     */
+    public abstract Session createSession();
 
-        public SpellCheckerSessionImpl(
-                SpellCheckerService service, String locale, ISpellCheckerSessionListener listener) {
-            mInternalServiceRef = new WeakReference<SpellCheckerService>(service);
-            mLocale = locale;
+    /**
+     * This abstract class should be overridden by a concrete implementation of a spell checker.
+     */
+    public abstract class Session {
+        private InternalISpellCheckerSession mInternalSession;
+
+        /**
+         * @hide
+         */
+        public final void setInternalISpellCheckerSession(InternalISpellCheckerSession session) {
+            mInternalSession = session;
+        }
+
+        /**
+         * This is called after the class is initialized, at which point it knows it can call
+         * getLocale() etc...
+         */
+        public abstract void onCreate();
+
+        /**
+         * Get suggestions for specified text in TextInfo.
+         * This function will run on the incoming IPC thread.
+         * So, this is not called on the main thread,
+         * but will be called in series on another thread.
+         * @param textInfo the text metadata
+         * @param suggestionsLimit the number of limit of suggestions returned
+         * @return SuggestionInfo which contains suggestions for textInfo
+         */
+        public abstract SuggestionsInfo onGetSuggestions(TextInfo textInfo, int suggestionsLimit);
+
+        /**
+         * A batch process of onGetSuggestions.
+         * This function will run on the incoming IPC thread.
+         * So, this is not called on the main thread,
+         * but will be called in series on another thread.
+         * @param textInfos an array of the text metadata
+         * @param suggestionsLimit the number of limit of suggestions returned
+         * @param sequentialWords true if textInfos can be treated as sequential words.
+         * @return an array of SuggestionInfo of onGetSuggestions
+         */
+        public SuggestionsInfo[] onGetSuggestionsMultiple(TextInfo[] textInfos,
+                int suggestionsLimit, boolean sequentialWords) {
+            final int length = textInfos.length;
+            final SuggestionsInfo[] retval = new SuggestionsInfo[length];
+            for (int i = 0; i < length; ++i) {
+                retval[i] = onGetSuggestions(textInfos[i], suggestionsLimit);
+                retval[i].setCookieAndSequence(
+                        textInfos[i].getCookie(), textInfos[i].getSequence());
+            }
+            return retval;
+        }
+
+        /**
+         * Request to abort all tasks executed in SpellChecker.
+         * This function will run on the incoming IPC thread.
+         * So, this is not called on the main thread,
+         * but will be called in series on another thread.
+         */
+        public void onCancel() {}
+
+        /**
+         * @return Locale for this session
+         */
+        public String getLocale() {
+            return mInternalSession.getLocale();
+        }
+
+        /**
+         * @return Bundle for this session
+         */
+        public Bundle getBundle() {
+            return mInternalSession.getBundle();
+        }
+    }
+
+    // Preventing from exposing ISpellCheckerSession.aidl, create an internal class.
+    private static class InternalISpellCheckerSession extends ISpellCheckerSession.Stub {
+        private final ISpellCheckerSessionListener mListener;
+        private final Session mSession;
+        private final String mLocale;
+        private final Bundle mBundle;
+
+        public InternalISpellCheckerSession(String locale, ISpellCheckerSessionListener listener,
+                Bundle bundle, Session session) {
             mListener = listener;
+            mSession = session;
+            mLocale = locale;
+            mBundle = bundle;
+            session.setInternalISpellCheckerSession(this);
         }
 
         @Override
-        public void getSuggestionsMultiple(
+        public void onGetSuggestionsMultiple(
                 TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
-            final SpellCheckerService service = mInternalServiceRef.get();
-            if (service == null) return;
             try {
                 mListener.onGetSuggestions(
-                        service.getSuggestionsMultiple(textInfos, mLocale,
-                                suggestionsLimit, sequentialWords));
+                        mSession.onGetSuggestionsMultiple(
+                                textInfos, suggestionsLimit, sequentialWords));
             } catch (RemoteException e) {
             }
         }
 
         @Override
-        public void cancel() {
-            final SpellCheckerService service = mInternalServiceRef.get();
-            if (service == null) return;
-            service.cancel();
+        public void onCancel() {
+            mSession.onCancel();
+        }
+
+        public String getLocale() {
+            return mLocale;
+        }
+
+        public Bundle getBundle() {
+            return mBundle;
         }
     }
 
@@ -137,10 +188,14 @@
 
         @Override
         public ISpellCheckerSession getISpellCheckerSession(
-                String locale, ISpellCheckerSessionListener listener) {
+                String locale, ISpellCheckerSessionListener listener, Bundle bundle) {
             final SpellCheckerService service = mInternalServiceRef.get();
             if (service == null) return null;
-            return new SpellCheckerSessionImpl(service, locale, listener);
+            final Session session = service.createSession();
+            final InternalISpellCheckerSession internalSession =
+                    new InternalISpellCheckerSession(locale, listener, bundle, session);
+            session.onCreate();
+            return internalSession;
         }
     }
 }
diff --git a/core/java/android/text/TextDirectionHeuristics.java b/core/java/android/text/TextDirectionHeuristics.java
index 5f9ffc5..20170bf 100644
--- a/core/java/android/text/TextDirectionHeuristics.java
+++ b/core/java/android/text/TextDirectionHeuristics.java
@@ -164,6 +164,7 @@
             case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
             case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING:
             case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE:
+            case Character.DIRECTIONALITY_ARABIC_NUMBER:
                 return TriState.TRUE;
             default:
                 return TriState.UNKNOWN;
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 66d2641..f2b6b1f 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -635,16 +635,8 @@
             destroySurface();
 
             // Create an EGL surface we can render into.
-            mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, holder, null);
-
-            if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
-                int error = sEgl.eglGetError();
-                if (error == EGL_BAD_NATIVE_WINDOW) {
-                    Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
-                    return null;
-                }
-                throw new RuntimeException("createWindowSurface failed "
-                        + getEGLErrorString(error));
+            if (!createSurface(holder)) {
+                return null;
             }
 
             /*
@@ -713,18 +705,34 @@
             // Cancels any existing buffer to ensure we'll get a buffer
             // of the right size before we call eglSwapBuffers
             sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-            sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
+
+            if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
+                sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
+                mEglSurface = null;
+                setEnabled(false);
+            }
+
+            if (holder.getSurface().isValid()) {
+                if (!createSurface(holder)) {
+                    return;
+                }
+                setEnabled(true);                
+            }
+        }
+
+        private boolean createSurface(SurfaceHolder holder) {
             mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, holder, null);
 
             if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
                 int error = sEgl.eglGetError();
                 if (error == EGL_BAD_NATIVE_WINDOW) {
                     Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
-                    return;
+                    return false;
                 }
                 throw new RuntimeException("createWindowSurface failed "
                         + getEGLErrorString(error));
             }
+            return true;
         }
 
         @Override
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 81cd798..c7bf8e3 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -184,6 +184,13 @@
      */
     int watchRotation(IRotationWatcher watcher);
 
+    /**
+     * Determine the preferred edge of the screen to pin the compact options menu against.
+     * @return a Gravity value for the options menu panel
+     * @hide
+     */
+    int getPreferredOptionsPanelGravity();
+
 	/**
 	 * Lock the device orientation to the current rotation. Sensor input will
 	 * be ignored until thawRotation() is called.
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 836867b..7a96a50 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -29,30 +29,84 @@
     private static final String LOG_TAG = "Surface";
     private static final boolean DEBUG_RELEASE = false;
     
+    /* orientations for setOrientation() */
+    public static final int ROTATION_0       = 0;
+    public static final int ROTATION_90      = 1;
+    public static final int ROTATION_180     = 2;
+    public static final int ROTATION_270     = 3;
+
+    /**
+     * Does this object hold a valid surface?  Returns true if it holds
+     * a physical surface, so lockCanvas() will succeed.  Otherwise
+     * returns false.
+     */
+    public native   boolean isValid();
+
+    /** Release the local reference to the server-side surface.  
+     * Always call release() when you're done with a Surface. This will
+     * make the surface invalid.
+     */
+    public native void release();
+
+    /** draw into a surface */
+    public Canvas lockCanvas(Rect dirty) throws OutOfResourcesException, IllegalArgumentException {
+        /*
+         * the dirty rectangle may be expanded to the surface's size, if for
+         * instance it has been resized or if the bits were lost, since the last
+         * call.
+         */
+        return lockCanvasNative(dirty);
+    }
+
+    /** unlock the surface and asks a page flip */
+    public native   void unlockCanvasAndPost(Canvas canvas);
+
+    /** 
+     * unlock the surface. the screen won't be updated until
+     * post() or postAll() is called
+     */
+    public native   void unlockCanvas(Canvas canvas);
+
+    @Override
+    public String toString() {
+        return "Surface(name=" + mName + ", identity=" + getIdentity() + ")";
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public native   void readFromParcel(Parcel source);
+    public native   void writeToParcel(Parcel dest, int flags);
+
+    /**
+     * Exception thrown when a surface couldn't be created or resized
+     */
+    public static class OutOfResourcesException extends Exception {
+        public OutOfResourcesException() {
+        }
+        public OutOfResourcesException(String name) {
+            super(name);
+        }
+    }
+    
+    /*
+     * -----------------------------------------------------------------------
+     * No user serviceable parts beyond this point
+     * -----------------------------------------------------------------------
+     */
+
     /* flags used in constructor (keep in sync with ISurfaceComposer.h) */
 
-    /** Surface is created hidden */
+    /** Surface is created hidden @hide */
     public static final int HIDDEN              = 0x00000004;
 
-    /** The surface is to be used by hardware accelerators or DMA engines 
-     * @deprecated this is ignored, this value is set automatically when needed.
-     */
-    @Deprecated
-    public static final int HARDWARE            = 0x00000010;
-
-    /** Implies "HARDWARE", the surface is to be used by the GPU;
-     * additionally the backbuffer is never preserved for these
-     * surfaces. 
-     * @deprecated this is ignored, this value is set automatically when needed.
-     */
-    @Deprecated
-    public static final int GPU                 = 0x00000028;
-
     /** The surface contains secure content, special measures will
      * be taken to disallow the surface's content to be copied from
      * another process. In particular, screenshots and VNC servers will
      * be disabled, but other measures can take place, for instance the
-     * surface might not be hardware accelerated. */
+     * surface might not be hardware accelerated. 
+     * @hide*/
     public static final int SECURE              = 0x00000080;
     
     /** Creates a surface where color components are interpreted as 
@@ -75,20 +129,11 @@
      *  
      *  In some rare situations, a non pre-multiplied surface is preferable.
      *  
+     *  @hide
      */
     public static final int NON_PREMULTIPLIED   = 0x00000100;
     
     /**
-     * Creates a surface without a rendering buffer. Instead, the content
-     * of the surface must be pushed by an external entity. This type
-     * of surface can be used for efficient camera preview or movie
-     * playback.
-     *
-     * @deprecated not support by the system anymore
-     */
-    @Deprecated
-    public static final int PUSH_BUFFERS        = 0x00000200;
-    /**
      * Indicates that the surface must be considered opaque, even if its
      * pixel format is set to translucent. This can be useful if an
      * application needs full RGBA 8888 support for instance but will
@@ -109,7 +154,7 @@
 
     // 0x1000 is reserved for an independent DRM protected flag in framework
 
-    /** Creates a normal surface. This is the default. */
+    /** Creates a normal surface. This is the default. @hide */
     public static final int FX_SURFACE_NORMAL   = 0x00000000;
     
     /** Creates a Blur surface. Everything behind this surface is blurred
@@ -117,6 +162,7 @@
      * is not settable or guaranteed.
      * It is an error to lock a Blur surface, since it doesn't have
      * a backing store.
+     * @hide
      */
     public static final int FX_SURFACE_BLUR     = 0x00010000;
     
@@ -124,55 +170,35 @@
      * by the amount specified in {@link #setAlpha}.
      * It is an error to lock a Dim surface, since it doesn't have
      * a backing store.
+     * @hide
      */
     public static final int FX_SURFACE_DIM     = 0x00020000;
 
-    /** Mask used for FX values above */
+    /** Mask used for FX values above @hide */
     public static final int FX_SURFACE_MASK     = 0x000F0000;
 
     /* flags used with setFlags() (keep in sync with ISurfaceComposer.h) */
     
-    /** Hide the surface. Equivalent to calling hide(). */
+    /** Hide the surface. Equivalent to calling hide(). @hide */
     public static final int SURFACE_HIDDEN    = 0x01;
     
-    /** Freeze the surface. Equivalent to calling freeze(). */
+    /** Freeze the surface. Equivalent to calling freeze(). @hide */
     public static final int SURFACE_FROZEN     = 0x02;
 
-    /**
-     * @deprecated Use {@link #SURFACE_FROZEN} instead.
-     */
-    @Deprecated
-    public static final int SURACE_FROZEN     = 0x02;
-
-    /** Enable dithering when compositing this surface */
+    /** Enable dithering when compositing this surface @hide */
     public static final int SURFACE_DITHER    = 0x04;
-
-    public static final int SURFACE_BLUR_FREEZE= 0x10;
-
-    /* orientations for setOrientation() */
-    public static final int ROTATION_0       = 0;
-    public static final int ROTATION_90      = 1;
-    public static final int ROTATION_180     = 2;
-    public static final int ROTATION_270     = 3;
     
-    /** 
-     * Disable the orientation animation 
-     * {@hide} 
-     */
+    /** Disable the orientation animation @hide */
     public static final int FLAGS_ORIENTATION_ANIMATION_DISABLE = 0x000000001;
 
     // The mSurfaceControl will only be present for Surfaces used by the window
     // server or system processes. When this class is parceled we defer to the
-    // mSurfaceControl to do the parceling. Otherwise we parcel the mNativeSurface.
-    @SuppressWarnings("unused")
+    // mSurfaceControl to do the parceling. Otherwise we parcel the
+    // mNativeSurface.
     private int mSurfaceControl;
-    @SuppressWarnings("unused")
     private int mSaveCount;
-    @SuppressWarnings("unused")
     private Canvas mCanvas;
-    @SuppressWarnings("unused")
     private int mNativeSurface;
-    @SuppressWarnings("unused")
     private int mSurfaceGenerationId;
     private String mName;
 
@@ -184,19 +210,8 @@
     // non compatibility mode.
     private Matrix mCompatibleMatrix;
 
-    @SuppressWarnings("unused")
     private Exception mCreationStack;
 
-    /**
-     * Exception thrown when a surface couldn't be created or resized
-     */
-    public static class OutOfResourcesException extends Exception {
-        public OutOfResourcesException() {
-        }
-        public OutOfResourcesException(String name) {
-            super(name);
-        }
-    }
 
     /*
      * We use a class initializer to allow the native code to cache some
@@ -219,10 +234,7 @@
         initFromSurfaceTexture(surfaceTexture);
     }
     
-    /**
-     * create a surface
-     * {@hide}
-     */
+    /** create a surface @hide */
     public Surface(SurfaceSession s,
             int pid, int display, int w, int h, int format, int flags)
         throws OutOfResourcesException {
@@ -233,10 +245,7 @@
         init(s,pid,null,display,w,h,format,flags);
     }
 
-    /**
-     * create a surface with a name
-     * {@hide}
-     */
+    /** create a surface with a name @hide */
     public Surface(SurfaceSession s,
             int pid, String name, int display, int w, int h, int format, int flags)
         throws OutOfResourcesException {
@@ -251,7 +260,7 @@
     /**
      * Create an empty surface, which will later be filled in by
      * readFromParcel().
-     * {@hide}
+     * @hide
      */
     public Surface() {
         if (DEBUG_RELEASE) {
@@ -260,16 +269,35 @@
         mCanvas = new CompatibleCanvas();
     }
 
+    private Surface(Parcel source) throws OutOfResourcesException {
+        init(source);
+    }
+
     /**
-     * A Canvas class that can handle the compatibility mode. This does two things differently.
+     * Copy another surface to this one.  This surface now holds a reference
+     * to the same data as the original surface, and is -not- the owner.
+     * @hide
+     */
+    public native void copyFrom(Surface o);
+    
+    /** @hide */
+    public int getGenerationId() {
+        return mSurfaceGenerationId;
+    }
+
+    /**
+     * A Canvas class that can handle the compatibility mode. This does two
+     * things differently.
      * <ul>
-     *  <li> Returns the width and height of the target metrics, rather than native.
-     *  For example, the canvas returns 320x480 even if an app is running in WVGA high density.
-     *  <li> Scales the matrix in setMatrix by the application scale, except if the matrix looks
-     *  like obtained from getMatrix. This is a hack to handle the case that an application
-     *  uses getMatrix to keep the original matrix, set matrix of its own, then set the original
-     *  matrix back. There is no perfect solution that works for all cases, and there are a lot of
-     *  cases that this model does not work, but we hope this works for many apps.
+     * <li>Returns the width and height of the target metrics, rather than
+     * native. For example, the canvas returns 320x480 even if an app is running
+     * in WVGA high density.
+     * <li>Scales the matrix in setMatrix by the application scale, except if
+     * the matrix looks like obtained from getMatrix. This is a hack to handle
+     * the case that an application uses getMatrix to keep the original matrix,
+     * set matrix of its own, then set the original matrix back. There is no
+     * perfect solution that works for all cases, and there are a lot of cases
+     * that this model does not work, but we hope this works for many apps.
      * </ul>
      */
     private class CompatibleCanvas extends Canvas {
@@ -318,7 +346,8 @@
     }
 
     /**
-     * Sets the translator used to scale canvas's width/height in compatibility mode.
+     * Sets the translator used to scale canvas's width/height in compatibility
+     * mode.
      */
     void setCompatibilityTranslator(Translator translator) {
         if (translator != null) {
@@ -328,73 +357,29 @@
         }
     }
     
-    /**
-     * Copy another surface to this one.  This surface now holds a reference
-     * to the same data as the original surface, and is -not- the owner.
-     * {@hide}
-     */
-    public native   void copyFrom(Surface o);
-    
-    /**
-     * Does this object hold a valid surface?  Returns true if it holds
-     * a physical surface, so lockCanvas() will succeed.  Otherwise
-     * returns false.
-     */
-    public native   boolean isValid();
-
-    /**
-     * @hide
-     */
-    public int getGenerationId() {
-        return mSurfaceGenerationId;
-    }
-    
     /** Free all server-side state associated with this surface and
-     * release this object's reference. {@hide} */
+     * release this object's reference. @hide */
     public native void destroy();
     
-    /** Release the local reference to the server-side surface. @hide */
-    public native void release();
+    private native Canvas lockCanvasNative(Rect dirty);   
     
-    /** draw into a surface */
-    public Canvas lockCanvas(Rect dirty) throws OutOfResourcesException, IllegalArgumentException
-    {
-        /* the dirty rectangle may be expanded to the surface's size, if
-         * for instance it has been resized or if the bits were lost, since
-         * the last call.
-         */
-        return lockCanvasNative(dirty);
-    }
-
-    private native Canvas lockCanvasNative(Rect dirty);
-
-    /** unlock the surface and asks a page flip */
-    public native   void unlockCanvasAndPost(Canvas canvas);
-
-    /** 
-     * unlock the surface. the screen won't be updated until
-     * post() or postAll() is called
+    /*
+     * set display parameters & screenshots
      */
-    public native   void unlockCanvas(Canvas canvas);
     
-    /** start/end a transaction {@hide} */
-    public static native   void openTransaction();
-    /** {@hide} */
-    public static native   void closeTransaction();
-
     /**
      * Freezes the specified display, No updating of the screen will occur
      * until unfreezeDisplay() is called. Everything else works as usual though,
      * in particular transactions.
      * @param display
-     * {@hide}
+     * @hide
      */
     public static native   void freezeDisplay(int display);
 
     /**
      * resume updating the specified display.
      * @param display
-     * {@hide}
+     * @hide
      */
     public static native   void unfreezeDisplay(int display);
 
@@ -403,7 +388,7 @@
      * @param display
      * @param orientation
      * @param flags
-     * {@hide}
+     * @hide
      */
     public static native   void setOrientation(int display, int orientation, int flags);
 
@@ -411,6 +396,7 @@
      * set the orientation of the given display.
      * @param display
      * @param orientation
+     * @hide
      */
     public static void setOrientation(int display, int orientation) {
         setOrientation(display, orientation, 0);
@@ -441,44 +427,43 @@
      */
     public static native Bitmap screenshot(int width, int height, int minLayer, int maxLayer);
 
-    /**
+    
+    /*
      * set surface parameters.
      * needs to be inside open/closeTransaction block
      */
+    
+    /** start a transaction @hide */
+    public static native   void openTransaction();
+    /** end a transaction @hide */
+    public static native   void closeTransaction();
+    /** @hide */
     public native   void setLayer(int zorder);
+    /** @hide */
     public native   void setPosition(int x, int y);
+    /** @hide */
     public native   void setSize(int w, int h);
-
+    /** @hide */
     public native   void hide();
+    /** @hide */
     public native   void show();
+    /** @hide */
     public native   void setTransparentRegionHint(Region region);
+    /** @hide */
     public native   void setAlpha(float alpha);
-    public native   void setMatrix(float dsdx, float dtdx,
-                                   float dsdy, float dtdy);
-
+    /** @hide */
+    public native   void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy);
+    /** @hide */
     public native   void freeze();
+    /** @hide */
     public native   void unfreeze();
-
+    /** @hide */
     public native   void setFreezeTint(int tint);
-
+    /** @hide */
     public native   void setFlags(int flags, int mask);
 
-    @Override
-    public String toString() {
-        return "Surface(name=" + mName + ", identity=" + getIdentity() + ")";
-    }
 
-    private Surface(Parcel source) throws OutOfResourcesException {
-        init(source);
-    }
-    
-    public int describeContents() {
-        return 0;
-    }
-
-    public native   void readFromParcel(Parcel source);
-    public native   void writeToParcel(Parcel dest, int flags);
-    
+   
     public static final Parcelable.Creator<Surface> CREATOR
             = new Parcelable.Creator<Surface>()
     {
@@ -496,7 +481,6 @@
         }
     };
 
-    /* no user serviceable parts here ... */
     @Override
     protected void finalize() throws Throwable {
         try {
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 96d6f09..76aa21f 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -204,6 +204,7 @@
             }
 
             mLayer.destroy();
+            mSurface.release();
             mSurface = null;
             mLayer = null;
         }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 935281a5..ad76928 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10221,6 +10221,7 @@
             }
 
             canvas.restoreToCount(restoreCount);
+            canvas.setBitmap(null);
 
             if (attachInfo != null) {
                 // Restore the cached Canvas for our siblings
@@ -10289,9 +10290,9 @@
         mPrivateFlags = flags;
 
         canvas.restoreToCount(restoreCount);
+        canvas.setBitmap(null);
 
         if (attachInfo != null) {
-            canvas.setBitmap(null);
             // Restore the cached Canvas for our siblings
             attachInfo.mCanvas = canvas;
         }
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index dbcbd6e..9520958 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -220,6 +220,7 @@
     private final int mMaximumDrawingCacheSize;
     private final int mOverscrollDistance;
     private final int mOverflingDistance;
+    private final boolean mFadingMarqueeEnabled;
 
     private boolean sHasPermanentMenuKey;
     private boolean sHasPermanentMenuKeySet;
@@ -246,6 +247,7 @@
         mMaximumDrawingCacheSize = MAXIMUM_DRAWING_CACHE_SIZE;
         mOverscrollDistance = OVERSCROLL_DISTANCE;
         mOverflingDistance = OVERFLING_DISTANCE;
+        mFadingMarqueeEnabled = true;
     }
 
     /**
@@ -297,6 +299,9 @@
                 sHasPermanentMenuKey = false;
             }
         }
+
+        mFadingMarqueeEnabled = res.getBoolean(
+                com.android.internal.R.bool.config_ui_enableFadingMarquee);
     }
 
     /**
@@ -673,4 +678,12 @@
     public boolean hasPermanentMenuKey() {
         return sHasPermanentMenuKey;
     }
+
+    /**
+     * @hide
+     * @return Whether or not marquee should use fading edges.
+     */
+    public boolean isFadingMarqueeEnabled() {
+        return mFadingMarqueeEnabled;
+    }
 }
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 96e550e..65e72c9 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -1094,6 +1094,9 @@
                             }
 
                             public void post(Object... data) {
+                                if (data[1] != null) {
+                                    ((Canvas) data[1]).setBitmap(null);
+                                }
                                 if (data[0] != null) {
                                     ((Bitmap) data[0]).recycle();
                                 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 911bf2f..ec4c5a29 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1253,6 +1253,11 @@
                         mScroller.abortAnimation();
                     }
                     disposeResizeBuffer();
+                    // Our surface is gone
+                    if (mAttachInfo.mHardwareRenderer != null &&
+                            mAttachInfo.mHardwareRenderer.isEnabled()) {
+                        mAttachInfo.mHardwareRenderer.destroy(true);
+                    }
                 } else if (surfaceGenerationId != mSurface.getGenerationId() &&
                         mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
                     fullRedrawNeeded = true;
@@ -1273,7 +1278,7 @@
                 }
             } catch (RemoteException e) {
             }
-            
+
             if (DEBUG_ORIENTATION) Log.v(
                     TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
 
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index 08ccd94..662137a 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -26,7 +26,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.media.AudioService;
 import android.media.AudioSystem;
@@ -36,13 +35,9 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.Vibrator;
-import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.widget.ImageView;
-import android.widget.ProgressBar;
 import android.widget.SeekBar;
-import android.widget.TextView;
-import android.widget.Toast;
 import android.widget.SeekBar.OnSeekBarChangeListener;
 
 import java.util.HashMap;
@@ -52,6 +47,10 @@
  *
  * This code really should be moved elsewhere.
  *
+ * Seriously, it really really should be moved elsewhere.  This is used by
+ * android.media.AudioService, which actually runs in the system process, to
+ * show the volume dialog when the user changes the volume.  What a mess.
+ *
  * @hide
  */
 public class VolumePanel extends Handler implements OnSeekBarChangeListener, View.OnClickListener
@@ -194,7 +193,7 @@
         window.setGravity(Gravity.TOP);
         WindowManager.LayoutParams lp = window.getAttributes();
         lp.token = null;
-        lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
+        lp.type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
         window.setAttributes(lp);
         window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
 
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index e07085c..6ac679c 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1213,5 +1213,10 @@
      * @see android.app.Activity#getVolumeControlStream()
      */
     public abstract int getVolumeControlStream();
-    
+
+    /**
+     * Set extra options that will influence the UI for this window.
+     * @param uiOptions Flags specifying extra options for this window.
+     */
+    public void setUiOptions(int uiOptions) { }
 }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index d1ad113..ff378a6 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -394,6 +394,13 @@
         public static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19;
 
         /**
+         * Window type: The volume level overlay/dialog shown when the user
+         * changes the system volume.
+         * @hide
+         */
+        public static final int TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20;
+
+        /**
          * End of types of system windows.
          */
         public static final int LAST_SYSTEM_WINDOW      = 2999;
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 9be2a67..c93b564 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -784,7 +784,7 @@
                 builder.append("\n");
             }
         } else {
-            builder.append("; recordCount: ").append(getAddedCount());
+            builder.append("; recordCount: ").append(getRecordCount());
         }
         return builder.toString();
     }
diff --git a/core/java/android/view/textservice/SpellCheckerInfo.java b/core/java/android/view/textservice/SpellCheckerInfo.java
index d88a39f..89cb11c 100644
--- a/core/java/android/view/textservice/SpellCheckerInfo.java
+++ b/core/java/android/view/textservice/SpellCheckerInfo.java
@@ -16,30 +16,122 @@
 
 package android.view.textservice;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.util.Xml;
+
+import java.io.IOException;
+import java.util.ArrayList;
 
 /**
  * This class is used to specify meta information of an spell checker.
  */
 public final class SpellCheckerInfo implements Parcelable {
+    private static final String TAG = SpellCheckerInfo.class.getSimpleName();
     private final ResolveInfo mService;
     private final String mId;
+    private final int mLabel;
+
+    /**
+     * The spell checker setting activity's name, used by the system settings to
+     * launch the setting activity.
+     */
+    private final String mSettingsActivityName;
+
+    /**
+     * The array of the subtypes.
+     */
+    private final ArrayList<SpellCheckerSubtype> mSubtypes = new ArrayList<SpellCheckerSubtype>();
 
     /**
      * Constructor.
      * @hide
      */
-    public SpellCheckerInfo(Context context, ResolveInfo service) {
+    public SpellCheckerInfo(Context context, ResolveInfo service)
+            throws XmlPullParserException, IOException {
         mService = service;
         ServiceInfo si = service.serviceInfo;
         mId = new ComponentName(si.packageName, si.name).flattenToShortString();
+
+        final PackageManager pm = context.getPackageManager();
+        int label = 0;
+        String settingsActivityComponent = null;
+        int isDefaultResId = 0;
+
+        XmlResourceParser parser = null;
+        try {
+            parser = si.loadXmlMetaData(pm, SpellCheckerSession.SERVICE_META_DATA);
+            if (parser == null) {
+                throw new XmlPullParserException("No "
+                        + SpellCheckerSession.SERVICE_META_DATA + " meta-data");
+            }
+
+            final Resources res = pm.getResourcesForApplication(si.applicationInfo);
+            final AttributeSet attrs = Xml.asAttributeSet(parser);
+            int type;
+            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                    && type != XmlPullParser.START_TAG) {
+            }
+
+            final String nodeName = parser.getName();
+            if (!"spell-checker".equals(nodeName)) {
+                throw new XmlPullParserException(
+                        "Meta-data does not start with spell-checker tag");
+            }
+
+            TypedArray sa = res.obtainAttributes(attrs,
+                    com.android.internal.R.styleable.SpellChecker);
+            label = sa.getResourceId(com.android.internal.R.styleable.SpellChecker_label, 0);
+            settingsActivityComponent = sa.getString(
+                    com.android.internal.R.styleable.SpellChecker_settingsActivity);
+            sa.recycle();
+
+            final int depth = parser.getDepth();
+            // Parse all subtypes
+            while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+                    && type != XmlPullParser.END_DOCUMENT) {
+                if (type == XmlPullParser.START_TAG) {
+                    final String subtypeNodeName = parser.getName();
+                    if (!"subtype".equals(subtypeNodeName)) {
+                        throw new XmlPullParserException(
+                                "Meta-data in spell-checker does not start with subtype tag");
+                    }
+                    final TypedArray a = res.obtainAttributes(
+                            attrs, com.android.internal.R.styleable.SpellChecker_Subtype);
+                    SpellCheckerSubtype subtype = new SpellCheckerSubtype(
+                            a.getResourceId(com.android.internal.R.styleable
+                                    .SpellChecker_Subtype_label, 0),
+                            a.getString(com.android.internal.R.styleable
+                                    .SpellChecker_Subtype_subtypeLocale),
+                            a.getString(com.android.internal.R.styleable
+                                    .SpellChecker_Subtype_subtypeExtraValue));
+                    mSubtypes.add(subtype);
+                }
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, "Caught exception: " + e);
+            throw new XmlPullParserException(
+                    "Unable to create context for: " + si.packageName);
+        } finally {
+            if (parser != null) parser.close();
+        }
+        mLabel = label;
+        mSettingsActivityName = settingsActivityComponent;
     }
 
     /**
@@ -47,8 +139,11 @@
      * @hide
      */
     public SpellCheckerInfo(Parcel source) {
+        mLabel = source.readInt();
         mId = source.readString();
+        mSettingsActivityName = source.readString();
         mService = ResolveInfo.CREATOR.createFromParcel(source);
+        source.readTypedList(mSubtypes, SpellCheckerSubtype.CREATOR);
     }
 
     /**
@@ -69,7 +164,7 @@
     }
 
     /**
-     * Return the .apk package that implements this input method.
+     * Return the .apk package that implements this.
      */
     public String getPackageName() {
         return mService.serviceInfo.packageName;
@@ -83,8 +178,11 @@
      */
     @Override
     public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mLabel);
         dest.writeString(mId);
+        dest.writeString(mSettingsActivityName);
         mService.writeToParcel(dest, flags);
+        dest.writeTypedList(mSubtypes);
     }
 
 
@@ -110,7 +208,8 @@
      * @param pm Supply a PackageManager used to load the spell checker's resources.
      */
     public CharSequence loadLabel(PackageManager pm) {
-        return mService.loadLabel(pm);
+        if (mLabel == 0 || pm == null) return "";
+        return pm.getText(getPackageName(), mLabel, mService.serviceInfo.applicationInfo);
     }
 
     /**
@@ -123,6 +222,35 @@
     }
 
     /**
+     * Return the class name of an activity that provides a settings UI.
+     * You can launch this activity be starting it with
+     * an {@link android.content.Intent} whose action is MAIN and with an
+     * explicit {@link android.content.ComponentName}
+     * composed of {@link #getPackageName} and the class name returned here.
+     *
+     * <p>A null will be returned if there is no settings activity.
+     */
+    public String getSettingsActivity() {
+        return mSettingsActivityName;
+    }
+
+    /**
+     * Return the count of the subtypes.
+     */
+    public int getSubtypeCount() {
+        return mSubtypes.size();
+    }
+
+    /**
+     * Return the subtype at the specified index.
+     *
+     * @param index the index of the subtype to return.
+     */
+    public SpellCheckerSubtype getSubtypeAt(int index) {
+        return mSubtypes.get(index);
+    }
+
+    /**
      * Used to make this class parcelable.
      */
     @Override
diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java
index bf07e71..b940b80 100644
--- a/core/java/android/view/textservice/SpellCheckerSession.java
+++ b/core/java/android/view/textservice/SpellCheckerSession.java
@@ -233,7 +233,7 @@
                 Log.w(TAG, "Cancel spell checker tasks.");
             }
             try {
-                mISpellCheckerSession.cancel();
+                mISpellCheckerSession.onCancel();
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to cancel " + e);
             }
@@ -247,7 +247,7 @@
                 Log.w(TAG, "Get suggestions from the spell checker.");
             }
             try {
-                mISpellCheckerSession.getSuggestionsMultiple(
+                mISpellCheckerSession.onGetSuggestionsMultiple(
                         scp.mTextInfos, scp.mSuggestionsLimit, scp.mSequentialWords);
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to get suggestions " + e);
diff --git a/core/java/android/view/textservice/SpellCheckerSubtype.aidl b/core/java/android/view/textservice/SpellCheckerSubtype.aidl
new file mode 100644
index 0000000..1c790e7
--- /dev/null
+++ b/core/java/android/view/textservice/SpellCheckerSubtype.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.view.textservice;
+
+parcelable SpellCheckerSubtype;
diff --git a/core/java/android/view/textservice/SpellCheckerSubtype.java b/core/java/android/view/textservice/SpellCheckerSubtype.java
new file mode 100644
index 0000000..dbd3081
--- /dev/null
+++ b/core/java/android/view/textservice/SpellCheckerSubtype.java
@@ -0,0 +1,159 @@
+/*
+ * 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 android.view.textservice;
+
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * This class is used to specify meta information of a subtype contained in a spell checker.
+ * Subtype can describe locale (e.g. en_US, fr_FR...) used for settings.
+ */
+public final class SpellCheckerSubtype implements Parcelable {
+
+    private final int mSubtypeHashCode;
+    private final int mSubtypeNameResId;
+    private final String mSubtypeLocale;
+    private final String mSubtypeExtraValue;
+
+    /**
+     * Constructor
+     * @param nameId The name of the subtype
+     * @param locale The locale supported by the subtype
+     * @param extraValue The extra value of the subtype
+     */
+    public SpellCheckerSubtype(int nameId, String locale, String extraValue) {
+        mSubtypeNameResId = nameId;
+        mSubtypeLocale = locale != null ? locale : "";
+        mSubtypeExtraValue = extraValue != null ? extraValue : "";
+        mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeExtraValue);
+    }
+
+    SpellCheckerSubtype(Parcel source) {
+        String s;
+        mSubtypeNameResId = source.readInt();
+        s = source.readString();
+        mSubtypeLocale = s != null ? s : "";
+        s = source.readString();
+        mSubtypeExtraValue = s != null ? s : "";
+        mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeExtraValue);
+    }
+
+    /**
+     * @return the name of the subtype
+     */
+    public int getNameResId() {
+        return mSubtypeNameResId;
+    }
+
+    /**
+     * @return the locale of the subtype
+     */
+    public String getLocale() {
+        return mSubtypeLocale;
+    }
+
+    /**
+     * @return the extra value of the subtype
+     */
+    public String getExtraValue() {
+        return mSubtypeExtraValue;
+    }
+
+    @Override
+    public int hashCode() {
+        return mSubtypeHashCode;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof SpellCheckerSubtype) {
+            SpellCheckerSubtype subtype = (SpellCheckerSubtype) o;
+            return (subtype.hashCode() == hashCode())
+                && (subtype.getNameResId() == getNameResId())
+                && (subtype.getLocale().equals(getLocale()))
+                && (subtype.getExtraValue().equals(getExtraValue()));
+        }
+        return false;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int parcelableFlags) {
+        dest.writeInt(mSubtypeNameResId);
+        dest.writeString(mSubtypeLocale);
+        dest.writeString(mSubtypeExtraValue);
+    }
+
+    public static final Parcelable.Creator<SpellCheckerSubtype> CREATOR
+            = new Parcelable.Creator<SpellCheckerSubtype>() {
+        @Override
+        public SpellCheckerSubtype createFromParcel(Parcel source) {
+            return new SpellCheckerSubtype(source);
+        }
+
+        @Override
+        public SpellCheckerSubtype[] newArray(int size) {
+            return new SpellCheckerSubtype[size];
+        }
+    };
+
+    private static int hashCodeInternal(String locale, String extraValue) {
+        return Arrays.hashCode(new Object[] {locale, extraValue});
+    }
+
+    /**
+     * Sort the list of subtypes
+     * @param context Context will be used for getting localized strings
+     * @param flags Flags for the sort order
+     * @param sci SpellCheckerInfo of which subtypes are subject to be sorted
+     * @param subtypeList List which will be sorted
+     * @return Sorted list of subtypes
+     * @hide
+     */
+    public static List<SpellCheckerSubtype> sort(Context context, int flags, SpellCheckerInfo sci,
+            List<SpellCheckerSubtype> subtypeList) {
+        if (sci == null) return subtypeList;
+        final HashSet<SpellCheckerSubtype> subtypesSet = new HashSet<SpellCheckerSubtype>(
+                subtypeList);
+        final ArrayList<SpellCheckerSubtype> sortedList = new ArrayList<SpellCheckerSubtype>();
+        int N = sci.getSubtypeCount();
+        for (int i = 0; i < N; ++i) {
+            SpellCheckerSubtype subtype = sci.getSubtypeAt(i);
+            if (subtypesSet.contains(subtype)) {
+                sortedList.add(subtype);
+                subtypesSet.remove(subtype);
+            }
+        }
+        // If subtypes in subtypesSet remain, that means these subtypes are not
+        // contained in sci, so the remaining subtypes will be appended.
+        for (SpellCheckerSubtype subtype: subtypesSet) {
+            sortedList.add(subtype);
+        }
+        return sortedList;
+    }
+}
diff --git a/core/java/android/view/textservice/SuggestionsInfo.java b/core/java/android/view/textservice/SuggestionsInfo.java
index 3332f1e..ed0f89d 100644
--- a/core/java/android/view/textservice/SuggestionsInfo.java
+++ b/core/java/android/view/textservice/SuggestionsInfo.java
@@ -34,9 +34,9 @@
     /**
      * Flag of the attributes of the suggestions that can be obtained by
      * {@link #getSuggestionsAttributes}: this tells that the text service thinks the requested
-     * word looks a typo.
+     * word looks like a typo.
      */
-    public static final int RESULT_ATTR_LOOKS_TYPO = 0x0002;
+    public static final int RESULT_ATTR_LOOKS_LIKE_TYPO = 0x0002;
     private final int mSuggestionsAttributes;
     private final String[] mSuggestions;
     private final boolean mSuggestionsAvailable;
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index a60eb24..d60ce4f 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -19,11 +19,11 @@
 import com.android.internal.textservice.ITextServicesManager;
 
 import android.content.Context;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
-import android.view.textservice.SpellCheckerSession;
 import android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener;
 
 import java.util.Locale;
@@ -74,7 +74,7 @@
      */
     // TODO: Add a method to get enabled spell checkers.
     // TODO: Handle referToSpellCheckerLanguageSettings
-    public SpellCheckerSession newSpellCheckerSession(Locale locale,
+    public SpellCheckerSession newSpellCheckerSession(Bundle bundle, Locale locale,
             SpellCheckerSessionListener listener, boolean referToSpellCheckerLanguageSettings) {
         if (listener == null) {
             throw new NullPointerException();
@@ -94,7 +94,7 @@
         try {
             sService.getSpellCheckerService(sci.getId(), localeString,
                     session.getTextServicesSessionListener(),
-                    session.getSpellCheckerSessionListener());
+                    session.getSpellCheckerSessionListener(), bundle);
         } catch (RemoteException e) {
             return null;
         }
diff --git a/core/java/android/webkit/DeviceMotionService.java b/core/java/android/webkit/DeviceMotionService.java
index 7d7a0f0..b4d5759 100755
--- a/core/java/android/webkit/DeviceMotionService.java
+++ b/core/java/android/webkit/DeviceMotionService.java
@@ -99,6 +99,7 @@
         mUpdateRunnable = new Runnable() {
             @Override
             public void run() {
+                assert mIsRunning;
                 mManager.onMotionChange(new Double(mLastAcceleration[0]),
                         new Double(mLastAcceleration[1]), new Double(mLastAcceleration[2]),
                         INTERVAL_MILLIS);
@@ -157,6 +158,11 @@
         assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName());
         assert(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER);
 
+        // We may get callbacks after the call to getSensorManager().unregisterListener() returns.
+        if (!mIsRunning) {
+            return;
+        }
+
         boolean firstData = mLastAcceleration == null;
         mLastAcceleration = event.values;
         if (firstData) {
diff --git a/core/java/android/webkit/DeviceOrientationService.java b/core/java/android/webkit/DeviceOrientationService.java
index f3c0576..47c8ab7 100755
--- a/core/java/android/webkit/DeviceOrientationService.java
+++ b/core/java/android/webkit/DeviceOrientationService.java
@@ -188,6 +188,7 @@
         assert(event.values.length == 3);
         assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName());
 
+        // We may get callbacks after the call to getSensorManager().unregisterListener() returns.
         if (!mIsRunning) {
             return;
         }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index f4fd551..7620a63 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -8405,9 +8405,9 @@
         }
     }
 
-    // Called by JNI to invalidate the View, given rectangle coordinates in
-    // content space
-    private void pageSwapCallback() {
+    /** @hide Called by JNI when pages are swapped (only occurs with hardware
+     * acceleration) */
+    protected void pageSwapCallback() {
         if (inEditingMode()) {
             didUpdateWebTextViewDimensions(ANYWHERE);
         }
@@ -8426,11 +8426,11 @@
         WebViewCore.ViewState viewState = draw.mViewState;
         boolean isPictureAfterFirstLayout = viewState != null;
 
-        // Request a callback on pageSwap (to reposition the webtextview)
-        boolean registerPageSwapCallback =
-            !mZoomManager.isFixedLengthAnimationInProgress() && inEditingMode();
-
         if (updateBaseLayer) {
+            // Request a callback on pageSwap (to reposition the webtextview)
+            boolean registerPageSwapCallback =
+                !mZoomManager.isFixedLengthAnimationInProgress() && inEditingMode();
+
             setBaseLayer(draw.mBaseLayer, draw.mInvalRegion,
                     getSettings().getShowVisualIndicator(),
                     isPictureAfterFirstLayout, registerPageSwapCallback);
@@ -9084,6 +9084,16 @@
         }
     }
 
+    /** @hide send content invalidate */
+    protected void contentInvalidateAll() {
+        mWebViewCore.sendMessage(EventHub.CONTENT_INVALIDATE_ALL);
+    }
+
+    /** @hide call pageSwapCallback upon next page swap */
+    protected void registerPageSwapCallback() {
+        nativeRegisterPageSwapCallback();
+    }
+
     /**
      * Begin collecting per-tile profiling data
      *
@@ -9245,6 +9255,7 @@
     private native void     nativeStopGL();
     private native Rect     nativeSubtractLayers(Rect content);
     private native int      nativeTextGeneration();
+    private native void     nativeRegisterPageSwapCallback();
     private native void     nativeTileProfilingStart();
     private native float    nativeTileProfilingStop();
     private native void     nativeTileProfilingClear();
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 8d8023b..400cdbd 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -999,6 +999,7 @@
         static final int DUMP_V8COUNTERS = 173;
 
         static final int SET_JS_FLAGS = 174;
+        static final int CONTENT_INVALIDATE_ALL = 175;
         // Geolocation
         static final int GEOLOCATION_PERMISSIONS_PROVIDE = 180;
 
@@ -1503,6 +1504,10 @@
                             nativeSetJsFlags((String)msg.obj);
                             break;
 
+                        case CONTENT_INVALIDATE_ALL:
+                            nativeContentInvalidateAll();
+                            break;
+
                         case SAVE_WEBARCHIVE:
                             WebView.SaveWebArchiveMessage saveMessage =
                                 (WebView.SaveWebArchiveMessage)msg.obj;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index cadf2ab..9737a5a9 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -628,6 +628,9 @@
     private int mGlowPaddingLeft;
     private int mGlowPaddingRight;
 
+    private int mLastAccessibilityScrollEventFromIndex;
+    private int mLastAccessibilityScrollEventToIndex;
+
     /**
      * Interface definition for a callback to be invoked when the list or grid
      * has been scrolled.
@@ -1265,6 +1268,24 @@
     }
 
     @Override
+    public void sendAccessibilityEvent(int eventType) {
+        // Since this class calls onScrollChanged even if the mFirstPosition and the
+        // child count have not changed we will avoid sending duplicate accessibility
+        // events.
+        if (eventType == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
+            final int lastPosition = mFirstPosition + getChildCount();
+            if (mLastAccessibilityScrollEventFromIndex == mFirstPosition
+                    && mLastAccessibilityScrollEventToIndex == lastPosition) {
+                return;   
+            } else {
+                mLastAccessibilityScrollEventFromIndex = mFirstPosition;
+                mLastAccessibilityScrollEventToIndex = lastPosition;       
+            }
+        }
+        super.sendAccessibilityEvent(eventType);
+    }
+
+    @Override
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         super.onInitializeAccessibilityEvent(event);
         event.setScrollable(true);
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 00c75a9..9f5737e 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -277,6 +277,7 @@
      *         called, false otherwise is returned.
      */
     public boolean performItemClick(View view, int position, long id) {
+        view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
         if (mOnItemClickListener != null) {
             playSoundEffect(SoundEffectConstants.CLICK);
             mOnItemClickListener.onItemClick(this, view, position, id);
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index 00ebe0d..7ad5d6c 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -116,6 +116,8 @@
 
     private int mOverlayPosition;
 
+    private boolean mMatchDragPosition;
+
     private static final int FADE_TIMEOUT = 1500;
 
     private final Rect mTmpRect = new Rect();
@@ -262,6 +264,9 @@
 
         ta.recycle();
 
+        mMatchDragPosition = context.getApplicationInfo().targetSdkVersion >=
+                android.os.Build.VERSION_CODES.HONEYCOMB;
+
         setScrollbarPosition(mList.getVerticalScrollbarPosition());
     }
     
@@ -417,7 +422,7 @@
             }
             return;
         }
-        if (totalItemCount - visibleItemCount > 0 && mState != STATE_DRAGGING ) {
+        if (totalItemCount - visibleItemCount > 0 && mState != STATE_DRAGGING) {
             mThumbY = getThumbPositionForListPosition(firstVisibleItem, visibleItemCount,
                     totalItemCount);
             if (mChangedBounds) {
@@ -595,7 +600,7 @@
         if (mSectionIndexer == null) {
             getSectionsFromIndexer();
         }
-        if (mSectionIndexer == null) {
+        if (mSectionIndexer == null || !mMatchDragPosition) {
             return ((mList.getHeight() - mThumbH) * firstVisibleItem)
                     / (totalItemCount - visibleItemCount);
         }
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index f354c6e..390002b 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -250,6 +250,7 @@
      * {@inheritDoc}
      */
     public GridLayout(Context context) {
+        //noinspection NullableProblems
         this(context, null);
     }
 
@@ -394,10 +395,6 @@
      */
     public void setUseDefaultMargins(boolean useDefaultMargins) {
         mUseDefaultMargins = useDefaultMargins;
-        if (useDefaultMargins) {
-            int padding = mDefaultGap;
-            setPadding(padding, padding, padding, padding);
-        }
         requestLayout();
     }
 
@@ -519,14 +516,6 @@
         return result;
     }
 
-    private static int sum(int[] a) {
-        int result = 0;
-        for (int i = 0, N = a.length; i < N; i++) {
-            result += a[i];
-        }
-        return result;
-    }
-
     @SuppressWarnings("unchecked")
     private static <T> T[] append(T[] a, T[] b) {
         T[] result = (T[]) Array.newInstance(a.getClass().getComponentType(), a.length + b.length);
@@ -553,6 +542,7 @@
         }
     }
 
+    /** @noinspection UnusedParameters*/
     private int getDefaultMargin(View c, boolean horizontal, boolean leading) {
         if (c.getClass() == Space.class) {
             return 0;
@@ -576,7 +566,7 @@
         return getDefaultMargin(c, isAtEdge, horizontal, leading);
     }
 
-    private int getMargin(View view, boolean horizontal, boolean leading) {
+    private int getMargin1(View view, boolean horizontal, boolean leading) {
         LayoutParams lp = getLayoutParams(view);
         int margin = horizontal ?
                 (leading ? lp.leftMargin : lp.rightMargin) :
@@ -584,6 +574,19 @@
         return margin == UNDEFINED ? getDefaultMarginValue(view, lp, horizontal, leading) : margin;
     }
 
+    private int getMargin(View view, boolean horizontal, boolean leading) {
+        if (mAlignmentMode == ALIGN_MARGINS) {
+            return getMargin1(view, horizontal, leading);
+        } else {
+            Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
+            int[] margins = leading ? axis.getLeadingMargins() : axis.getTrailingMargins();
+            LayoutParams lp = getLayoutParams(view);
+            Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
+            int index = leading ? spec.span.min : spec.span.max;
+            return margins[index];
+        }
+    }
+
     private int getTotalMargin(View child, boolean horizontal) {
         return getMargin(child, horizontal, true) + getMargin(child, horizontal, false);
     }
@@ -733,13 +736,8 @@
         graphics.drawLine(dx + x1, dy + y1, dx + x2, dy + y2, paint);
     }
 
-    private void drawRectangle(Canvas graphics, int x1, int y1, int x2, int y2, Paint paint) {
-        x2 = x2 - 1;
-        y2 = y2 - 1;
-        graphics.drawLine(x1, y1, x1, y2, paint);
-        graphics.drawLine(x1, y1, x2, y1, paint);
-        graphics.drawLine(x1, y2, x2, y2, paint);
-        graphics.drawLine(x2, y1, x2, y2, paint);
+    private static void drawRect(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint) {
+        canvas.drawRect(x1, y1, x2 - 1, y2 - 1, paint);
     }
 
     @Override
@@ -751,6 +749,7 @@
             int width = getWidth() - getPaddingLeft() - getPaddingRight();
 
             Paint paint = new Paint();
+            paint.setStyle(Paint.Style.STROKE);
             paint.setColor(Color.argb(50, 255, 255, 255));
 
             int[] xs = mHorizontalAxis.locations;
@@ -773,22 +772,18 @@
             paint.setColor(Color.BLUE);
             for (int i = 0; i < getChildCount(); i++) {
                 View c = getChildAt(i);
-                drawRectangle(canvas,
-                        c.getLeft(),
-                        c.getTop(),
-                        c.getRight(),
-                        c.getBottom(), paint);
+                drawRect(canvas, c.getLeft(), c.getTop(), c.getRight(), c.getBottom(), paint);
             }
 
             // Draw margins
             paint.setColor(Color.MAGENTA);
             for (int i = 0; i < getChildCount(); i++) {
                 View c = getChildAt(i);
-                drawRectangle(canvas,
-                        c.getLeft() - getMargin(c, true, true),
-                        c.getTop() - getMargin(c, false, true),
-                        c.getRight() + getMargin(c, true, false),
-                        c.getBottom() + getMargin(c, false, false), paint);
+                drawRect(canvas,
+                        c.getLeft() - getMargin1(c, true, true),
+                        c.getTop() - getMargin1(c, false, true),
+                        c.getRight() + getMargin1(c, true, false),
+                        c.getBottom() + getMargin1(c, false, false), paint);
             }
         }
     }
@@ -875,11 +870,7 @@
         if (isGone(c)) {
             return 0;
         }
-        int result = getMeasurement(c, horizontal);
-        if (mAlignmentMode == ALIGN_MARGINS) {
-            return result + getTotalMargin(c, horizontal);
-        }
-        return result;
+        return getMeasurement(c, horizontal) + getTotalMargin(c, horizontal);
     }
 
     @Override
@@ -920,6 +911,9 @@
         mHorizontalAxis.layout(targetWidth - paddingLeft - paddingRight);
         mVerticalAxis.layout(targetHeight - paddingTop - paddingBottom);
 
+        int[] hLocations = mHorizontalAxis.getLocations();
+        int[] vLocations = mVerticalAxis.getLocations();
+
         for (int i = 0, N = getChildCount(); i < N; i++) {
             View c = getChildAt(i);
             if (isGone(c)) continue;
@@ -930,11 +924,11 @@
             Interval colSpan = columnSpec.span;
             Interval rowSpan = rowSpec.span;
 
-            int x1 = mHorizontalAxis.getLocationIncludingMargin(true, colSpan.min);
-            int y1 = mVerticalAxis.getLocationIncludingMargin(true, rowSpan.min);
+            int x1 = hLocations[colSpan.min];
+            int y1 = vLocations[rowSpan.min];
 
-            int x2 = mHorizontalAxis.getLocationIncludingMargin(false, colSpan.max);
-            int y2 = mVerticalAxis.getLocationIncludingMargin(false, rowSpan.max);
+            int x2 = hLocations[colSpan.max];
+            int y2 = vLocations[rowSpan.max];
 
             int cellWidth = x2 - x1;
             int cellHeight = y2 - y1;
@@ -951,36 +945,29 @@
             Bounds rowBounds = mVerticalAxis.getGroupBounds().getValue(i);
 
             // Gravity offsets: the location of the alignment group relative to its cell group.
+            //noinspection NullableProblems
             int c2ax = protect(hAlign.getAlignmentValue(null, cellWidth - colBounds.size(true)));
+            //noinspection NullableProblems
             int c2ay = protect(vAlign.getAlignmentValue(null, cellHeight - rowBounds.size(true)));
 
-            if (mAlignmentMode == ALIGN_MARGINS) {
-                int leftMargin = getMargin(c, true, true);
-                int topMargin = getMargin(c, false, true);
-                int rightMargin = getMargin(c, true, false);
-                int bottomMargin = getMargin(c, false, false);
+            int leftMargin = getMargin(c, true, true);
+            int topMargin = getMargin(c, false, true);
+            int rightMargin = getMargin(c, true, false);
+            int bottomMargin = getMargin(c, false, false);
 
-                // Same calculation as getMeasurementIncludingMargin()
-                int mWidth = leftMargin + pWidth + rightMargin;
-                int mHeight = topMargin + pHeight + bottomMargin;
+            // Same calculation as getMeasurementIncludingMargin()
+            int mWidth = leftMargin + pWidth + rightMargin;
+            int mHeight = topMargin + pHeight + bottomMargin;
 
-                // Alignment offsets: the location of the view relative to its alignment group.
-                int a2vx = colBounds.getOffset(c, hAlign, mWidth);
-                int a2vy = rowBounds.getOffset(c, vAlign, mHeight);
+            // Alignment offsets: the location of the view relative to its alignment group.
+            int a2vx = colBounds.getOffset(c, hAlign, mWidth);
+            int a2vy = rowBounds.getOffset(c, vAlign, mHeight);
 
-                dx = c2ax + a2vx + leftMargin;
-                dy = c2ay + a2vy + topMargin;
+            dx = c2ax + a2vx + leftMargin;
+            dy = c2ay + a2vy + topMargin;
 
-                cellWidth -= leftMargin + rightMargin;
-                cellHeight -= topMargin + bottomMargin;
-            } else {
-                // Alignment offsets: the location of the view relative to its alignment group.
-                int a2vx = colBounds.getOffset(c, hAlign, pWidth);
-                int a2vy = rowBounds.getOffset(c, vAlign, pHeight);
-
-                dx = c2ax + a2vx;
-                dy = c2ay + a2vy;
-            }
+            cellWidth -= leftMargin + rightMargin;
+            cellHeight -= topMargin + bottomMargin;
 
             int type = PRF;
             int width = hAlign.getSizeInCell(c, pWidth, cellWidth, type);
@@ -1366,10 +1353,9 @@
             String axis = horizontal ? "horizontal" : "vertical";
             int N = getCount() + 1; // The number of vertices is the number of columns/rows + 1.
 
-            boolean changed = false;
             // We take one extra pass over traditional Bellman-Ford (and omit their final step)
             for (int i = 0; i < N; i++) {
-                changed = false;
+                boolean changed = false;
                 for (int j = 0, length = arcs.length; j < length; j++) {
                     changed |= relax(locations, arcs[j]);
                 }
@@ -1420,7 +1406,7 @@
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
                 Interval span = spec.span;
                 int index = leading ? span.min : span.max;
-                margins[index] = max(margins[index], getMargin(c, horizontal, leading));
+                margins[index] = max(margins[index], getMargin1(c, horizontal, leading));
             }
         }
 
@@ -1446,34 +1432,8 @@
             return trailingMargins;
         }
 
-        private void addMargins() {
-            int[] leadingMargins = getLeadingMargins();
-            int[] trailingMargins = getTrailingMargins();
-
-            int delta = 0;
-            for (int i = 0, N = getCount(); i < N; i++) {
-                int margins = leadingMargins[i] + trailingMargins[i + 1];
-                delta += margins;
-                locations[i + 1] += delta;
-            }
-        }
-
-        private int getLocationIncludingMargin(boolean leading, int index) {
-            int location = locations[index];
-            int margin;
-            if (mAlignmentMode != ALIGN_MARGINS) {
-                margin = (leading ? leadingMargins : trailingMargins)[index];
-            } else {
-                margin = 0;
-            }
-            return leading ? (location + margin) : (location - margin);
-        }
-
         private void computeLocations(int[] a) {
             solve1(getArcs(), a);
-            if (mAlignmentMode != ALIGN_MARGINS) {
-                addMargins();
-            }
         }
 
         private int[] getLocations() {
@@ -1495,12 +1455,6 @@
         }
 
         private void setParentConstraints(int min, int max) {
-            if (mAlignmentMode != ALIGN_MARGINS) {
-                int margins = sum(getLeadingMargins()) + sum(getTrailingMargins());
-                min -= margins;
-                max -= margins;
-            }
-
             parentMin.value = min;
             parentMax.value = -max;
             locationsValid = false;
@@ -1905,10 +1859,6 @@
             this.values = compact(values, index);
         }
 
-        private K getKey(int i) {
-            return keys[index[i]];
-        }
-
         private V getValue(int i) {
             return values[index[i]];
         }
@@ -1958,8 +1908,6 @@
     of the values for each View.
     */
     private static class Bounds {
-        private static final Bounds GONE = new Bounds();
-
         public int before;
         public int after;
         public int flexibility; // we're flexible iff all included specs are flexible
@@ -1995,8 +1943,8 @@
         protected final void include(View c, Spec spec, GridLayout gridLayout, Axis axis) {
             this.flexibility &= spec.getFlexibility();
             int size = gridLayout.getMeasurementIncludingMargin(c, axis.horizontal);
-            // todo test this works correctly when the returned value is UNDEFINED
             Alignment alignment = gridLayout.getAlignment(spec.alignment, axis.horizontal);
+            // todo test this works correctly when the returned value is UNDEFINED
             int before = alignment.getAlignmentValue(c, size);
             include(before, size - before);
         }
@@ -2079,6 +2027,7 @@
             if (max != interval.max) {
                 return false;
             }
+            //noinspection RedundantIfStatement
             if (min != interval.min) {
                 return false;
             }
@@ -2113,57 +2062,33 @@
      * For column groups, this specifies the horizontal alignment.
      */
     public static class Spec {
-        private static final int UNDEFINED_FLEXIBILITY = UNDEFINED;
-
         final Interval span;
-
         final Alignment alignment;
 
-        /**
-         * The <em>flexibility</em> property tells GridLayout how to derive minimum and maximum size
-         * values for a component. Specifications are made with respect to a child's
-         * 'measured size'. A child's measured size is, in turn, controlled by its
-         * height and width layout parameters which either specify a size or, in
-         * the case of {@link LayoutParams#WRAP_CONTENT WRAP_CONTENT}, defer to
-         * the computed size of the component.
-         * <p>
-         * A cell group is flexible only if <em>all</em> of its components are flexible.
-         * <p>
-         * By default, flexibility is {@link #INFLEXIBLE} only when alignment/gravity is undefined.
-         */
-        final int flexibility;
-
-        private Spec(Interval span, Alignment alignment, int flexibility) {
+        private Spec(Interval span, Alignment alignment) {
             this.span = span;
             this.alignment = alignment;
-            this.flexibility = flexibility;
         }
 
         /* Copying constructor */
         private Spec(Spec that) {
-            this(that.span, that.alignment, that.flexibility);
+            this(that.span, that.alignment);
         }
 
         private Spec(int start, int size, Alignment alignment) {
-            this(new Interval(start, start + size), alignment, UNDEFINED);
+            this(new Interval(start, start + size), alignment);
         }
 
         private Spec copyWriteSpan(Interval span) {
-            return new Spec(span, alignment, flexibility);
+            return new Spec(span, alignment);
         }
 
         private Spec copyWriteAlignment(Alignment alignment) {
-            return new Spec(span, alignment, flexibility);
-        }
-
-        private static int defaultFlexibility(Alignment alignment) {
-            return (alignment == UNDEFINED_ALIGNMENT) ? INFLEXIBLE : CAN_STRETCH;
+            return new Spec(span, alignment);
         }
 
         int getFlexibility() {
-            return (flexibility != UNDEFINED_FLEXIBILITY) ?
-                    flexibility :
-                    defaultFlexibility(alignment);
+            return (alignment == UNDEFINED_ALIGNMENT) ? INFLEXIBLE : CAN_STRETCH;
         }
 
         /**
@@ -2190,6 +2115,7 @@
             if (!alignment.equals(spec.alignment)) {
                 return false;
             }
+            //noinspection RedundantIfStatement
             if (!span.equals(spec.span)) {
                 return false;
             }
@@ -2447,15 +2373,5 @@
 
     private static final int INFLEXIBLE = 0;
 
-    /**
-     * Indicates that a view's size should be greater than or equal to the size specified by
-     * its layout parameters.
-     *
-     * @deprecated Please use {@link #spec(int, int, Alignment)} instead,
-     * all spec's that define alignment (gravity) are assumed to able to stretch.
-     *
-     * @hide
-     */
-    @Deprecated
-    public static final int CAN_STRETCH = 2;
+    private static final int CAN_STRETCH = 2;
 }
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 299e1ff..fc60949 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -83,6 +83,7 @@
     // Avoid allocations...
     private RectF mTempSrc = new RectF();
     private RectF mTempDst = new RectF();
+    private float[] mTempPoints;
 
     private boolean mCropToPadding;
 
@@ -337,7 +338,6 @@
         }
     }
 
-    
     /**
      * Sets a drawable as the content of this ImageView.
      * 
@@ -347,8 +347,31 @@
         if (mDrawable != drawable) {
             mResource = 0;
             mUri = null;
+            int oldWidth = mDrawableWidth;
+            int oldHeight = mDrawableHeight;
             updateDrawable(drawable);
-            requestLayout();
+
+            boolean needsLayout;
+            if (mScaleType == ScaleType.CENTER) {
+                needsLayout = mDrawableWidth != oldWidth || mDrawableHeight != oldHeight;
+            } else {
+                if (mTempPoints == null) {
+                    mTempPoints = new float[4];
+                }
+                float[] points = mTempPoints;
+                points[0] = oldWidth;
+                points[1] = oldHeight;
+                points[2] = mDrawableWidth;
+                points[3] = mDrawableHeight;
+                if (!mMatrix.isIdentity()) {
+                    mMatrix.mapPoints(points);
+                }
+                needsLayout = points[0] != points[2] || points[1] != points[3];
+            }
+
+            if (needsLayout) {
+                requestLayout();
+            }
             invalidate();
         }
     }
@@ -643,6 +666,9 @@
         // We are allowed to change the view's height
         boolean resizeHeight = false;
         
+        final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
+        final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
+
         if (mDrawable == null) {
             // If no drawable, its intrinsic size is 0.
             mDrawableWidth = -1;
@@ -657,10 +683,6 @@
             // We are supposed to adjust view bounds to match the aspect
             // ratio of our drawable. See if that is possible.
             if (mAdjustViewBounds) {
-                
-                int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
-                int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
-                
                 resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;
                 resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;
                 
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index f057d07..307959b 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -1092,7 +1092,7 @@
         }
 
         final int listContent = mDropDownList.measureHeightOfChildren(MeasureSpec.UNSPECIFIED,
-                0, ListView.NO_POSITION, maxHeight - otherHeights, 2);
+                0, ListView.NO_POSITION, maxHeight - otherHeights, -1);
         // add padding only if the list has items in it, that way we don't show
         // the popup if it is not needed
         if (listContent > 0) otherHeights += padding;
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 3a22bfb..8c288d10 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -112,6 +112,7 @@
     private boolean mClearingFocus;
     private int mMaxWidth;
     private boolean mVoiceButtonEnabled;
+    private CharSequence mOldQueryText;
     private CharSequence mUserQuery;
     private boolean mExpandedInActionView;
 
@@ -462,6 +463,7 @@
         if (mIconifiedByDefault == iconified) return;
         mIconifiedByDefault = iconified;
         updateViewsVisibility(iconified);
+        updateQueryHint();
     }
 
     /**
@@ -970,9 +972,10 @@
         updateVoiceButton(!hasText);
         updateCloseButton();
         updateSubmitArea();
-        if (mOnQueryChangeListener != null) {
+        if (mOnQueryChangeListener != null && !TextUtils.equals(newText, mOldQueryText)) {
             mOnQueryChangeListener.onQueryTextChange(newText.toString());
         }
+        mOldQueryText = newText.toString();
     }
 
     private void onSubmitQuery() {
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index c4ba7c8..4b08f2d 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -1406,6 +1406,7 @@
             v.setTranslationX(translationX);
 
             drawOutline(mCanvas, bitmap);
+            mCanvas.setBitmap(null);
             return bitmap;
         }
 
@@ -1417,6 +1418,7 @@
             dest.drawColor(0, PorterDuff.Mode.CLEAR);
             dest.setMatrix(mIdentityMatrix);
             dest.drawBitmap(mask, xy[0], xy[1], mHolographicPaint);
+            mMaskCanvas.setBitmap(null);
             mask.recycle();
         }
     }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index ab66676..04cf69b 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -343,6 +343,9 @@
     private Drawable mSelectHandleRight;
     private Drawable mSelectHandleCenter;
 
+    // Global listener that detects changes in the global position of the TextView
+    private PositionListener mPositionListener;
+
     private float mLastDownPositionX, mLastDownPositionY;
     private Callback mCustomSelectionActionModeCallback;
 
@@ -394,7 +397,7 @@
          */
         boolean onEditorAction(TextView v, int actionId, KeyEvent event);
     }
-    
+
     public TextView(Context context) {
         this(context, null);
     }
@@ -999,7 +1002,8 @@
                 setEllipsize(TextUtils.TruncateAt.END);
                 break;
             case 4:
-                setHorizontalFadingEdgeEnabled(true);
+                setHorizontalFadingEdgeEnabled(
+                        ViewConfiguration.get(context).isFadingMarqueeEnabled());
                 setEllipsize(TextUtils.TruncateAt.MARQUEE);
                 break;
         }
@@ -2080,7 +2084,7 @@
                                        TextAppearance_textStyle, -1);
 
         setTypefaceByIndex(typefaceIndex, styleIndex);
-        
+
         if (appearance.getBoolean(com.android.internal.R.styleable.TextAppearance_textAllCaps,
                 false)) {
             setTransformationMethod(new AllCapsTransformationMethod(getContext()));
@@ -3018,7 +3022,7 @@
      * To style your strings, attach android.text.style.* objects to a
      * {@link android.text.SpannableString SpannableString}, or see the
      * <a href="{@docRoot}guide/topics/resources/available-resources.html#stringresources">
-     * Available Resource Types</a> documentation for an example of setting 
+     * Available Resource Types</a> documentation for an example of setting
      * formatted text in the XML resource file.
      *
      * @attr ref android.R.styleable#TextView_text
@@ -3067,7 +3071,8 @@
 
         if (text instanceof Spanned &&
             ((Spanned) text).getSpanStart(TextUtils.TruncateAt.MARQUEE) >= 0) {
-            setHorizontalFadingEdgeEnabled(true);
+            setHorizontalFadingEdgeEnabled(
+                    ViewConfiguration.get(mContext).isFadingMarqueeEnabled());
             setEllipsize(TextUtils.TruncateAt.MARQUEE);
         }
 
@@ -8444,6 +8449,17 @@
         info.setPassword(isPassword);
     }
 
+    @Override
+    public void sendAccessibilityEvent(int eventType) {
+        // Do not send scroll events since first they are not interesting for
+        // accessibility and second such events a generated too frequently.
+        // For details see the implementation of bringTextIntoView().
+        if (eventType == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
+            return;
+        }
+        super.sendAccessibilityEvent(eventType);
+    }
+
     void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText,
             int fromIndex, int removedCount, int addedCount) {
         AccessibilityEvent event =
@@ -8755,32 +8771,247 @@
         return ((minOffset >= selectionStart) && (maxOffset < selectionEnd));
     }
 
+    private PositionListener getPositionListener() {
+        if (mPositionListener == null) {
+            mPositionListener = new PositionListener();
+        }
+        return mPositionListener;
+    }
+
+    private interface TextViewPositionListener {
+        public void updatePosition(int parentPositionX, int parentPositionY, boolean modified);
+    }
+
+    private class PositionListener implements ViewTreeObserver.OnPreDrawListener {
+        // 3 handles, 2 ActionPopup (suggestionsPopup first hides the others)
+        private final int MAXIMUM_NUMBER_OF_LISTENERS = 5;
+        private TextViewPositionListener[] mPositionListeners =
+                new TextViewPositionListener[MAXIMUM_NUMBER_OF_LISTENERS];
+        private boolean mCanMove[] = new boolean[MAXIMUM_NUMBER_OF_LISTENERS];
+        private boolean mPositionHasChanged = true;
+        // Absolute position of the TextView with respect to its parent window
+        private int mPositionX, mPositionY;
+        private int mNumberOfListeners;
+
+        public void addSubscriber(TextViewPositionListener positionListener, boolean canMove) {
+            if (mNumberOfListeners == 0) {
+                updatePosition();
+                ViewTreeObserver vto = TextView.this.getViewTreeObserver();
+                vto.addOnPreDrawListener(this);
+            }
+
+            int emptySlotIndex = -1;
+            for (int i = 0; i < MAXIMUM_NUMBER_OF_LISTENERS; i++) {
+                TextViewPositionListener listener = mPositionListeners[i];
+                if (listener == positionListener) {
+                    return;
+                } else if (emptySlotIndex < 0 && listener == null) {
+                    emptySlotIndex = i;
+                }
+            }
+
+            mPositionListeners[emptySlotIndex] = positionListener;
+            mCanMove[emptySlotIndex] = canMove;
+            mNumberOfListeners++;
+        }
+
+        public void removeSubscriber(TextViewPositionListener positionListener) {
+            for (int i = 0; i < MAXIMUM_NUMBER_OF_LISTENERS; i++) {
+                if (mPositionListeners[i] == positionListener) {
+                    mPositionListeners[i] = null;
+                    mNumberOfListeners--;
+                    break;
+                }
+            }
+
+            if (mNumberOfListeners == 0) {
+                ViewTreeObserver vto = TextView.this.getViewTreeObserver();
+                vto.removeOnPreDrawListener(this);
+            }
+        }
+
+        public int getPositionX() {
+            return mPositionX;
+        }
+
+        public int getPositionY() {
+            return mPositionY;
+        }
+
+        @Override
+        public boolean onPreDraw() {
+            updatePosition();
+
+            for (int i = 0; i < MAXIMUM_NUMBER_OF_LISTENERS; i++) {
+                if (mPositionHasChanged || mCanMove[i]) {
+                    TextViewPositionListener positionListener = mPositionListeners[i];
+                    if (positionListener != null) {
+                        positionListener.updatePosition(mPositionX, mPositionY,
+                                mPositionHasChanged);
+                    }
+                }
+            }
+
+            return true;
+        }
+
+        private void updatePosition() {
+            TextView.this.getLocationInWindow(mTempCoords);
+
+            mPositionHasChanged = mTempCoords[0] != mPositionX || mTempCoords[1] != mPositionY;
+
+            mPositionX = mTempCoords[0];
+            mPositionY = mTempCoords[1];
+        }
+
+        public boolean isVisible(int positionX, int positionY) {
+            final TextView textView = TextView.this;
+
+            if (mTempRect == null) mTempRect = new Rect();
+            final Rect clip = mTempRect;
+            clip.left = getCompoundPaddingLeft();
+            clip.top = getExtendedPaddingTop();
+            clip.right = textView.getWidth() - getCompoundPaddingRight();
+            clip.bottom = textView.getHeight() - getExtendedPaddingBottom();
+
+            final ViewParent parent = textView.getParent();
+            if (parent == null || !parent.getChildVisibleRect(textView, clip, null)) {
+                return false;
+            }
+
+            int posX = mPositionX + positionX;
+            int posY = mPositionY + positionY;
+
+            // Offset by 1 to take into account 0.5 and int rounding around getPrimaryHorizontal.
+            return posX >= clip.left - 1 && posX <= clip.right + 1 &&
+                    posY >= clip.top && posY <= clip.bottom;
+        }
+
+        public boolean isOffsetVisible(int offset) {
+            final int line = mLayout.getLineForOffset(offset);
+            final int lineBottom = mLayout.getLineBottom(line);
+            final int primaryHorizontal = (int) mLayout.getPrimaryHorizontal(offset);
+            return isVisible(primaryHorizontal, lineBottom);
+        }
+    }
+
+    private abstract class PinnedPopupWindow implements TextViewPositionListener {
+        protected PopupWindow mPopupWindow;
+        protected LinearLayout mContentView;
+        int mPositionX, mPositionY;
+
+        protected abstract void createPopupWindow();
+        protected abstract void initContentView();
+        protected abstract int getTextOffset();
+        protected abstract int getVerticalLocalPosition(int line);
+        protected abstract int clipVertically(int positionY);
+
+        public PinnedPopupWindow() {
+            createPopupWindow();
+
+            mPopupWindow.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
+            mPopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
+            mPopupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
+
+            mContentView = new LinearLayout(TextView.this.getContext());
+            LayoutParams wrapContent = new LayoutParams(
+                    ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+            mContentView.setLayoutParams(wrapContent);
+
+            initContentView();
+            mPopupWindow.setContentView(mContentView);
+        }
+
+        public void show() {
+            final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+            mContentView.measure(
+                    View.MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels,
+                            View.MeasureSpec.AT_MOST),
+                    View.MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels,
+                            View.MeasureSpec.AT_MOST));
+
+            TextView.this.getPositionListener().addSubscriber(this, false);
+
+            computeLocalPosition();
+
+            final PositionListener positionListener = TextView.this.getPositionListener();
+            updatePosition(positionListener.getPositionX(), positionListener.getPositionY());
+        }
+
+        private void computeLocalPosition() {
+            final int offset = getTextOffset();
+
+            final int width = mContentView.getMeasuredWidth();
+            mPositionX = (int) (mLayout.getPrimaryHorizontal(offset) - width / 2.0f);
+            mPositionX += viewportToContentHorizontalOffset();
+
+            final int line = mLayout.getLineForOffset(offset);
+            mPositionY = getVerticalLocalPosition(line);
+            mPositionY += viewportToContentVerticalOffset();
+        }
+
+        private void updatePosition(int parentPositionX, int parentPositionY) {
+            int positionX = parentPositionX + mPositionX;
+            int positionY = parentPositionY + mPositionY;
+
+            positionY = clipVertically(positionY);
+
+            // Horizontal clipping
+            final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+            final int width = mContentView.getMeasuredWidth();
+            positionX = Math.min(displayMetrics.widthPixels - width, positionX);
+            positionX = Math.max(0, positionX);
+
+            if (isShowing()) {
+                mPopupWindow.update(positionX, positionY, -1, -1);
+            } else {
+                mPopupWindow.showAtLocation(TextView.this, Gravity.NO_GRAVITY,
+                        positionX, positionY);
+            }
+        }
+
+        public void hide() {
+            mPopupWindow.dismiss();
+            TextView.this.getPositionListener().removeSubscriber(this);
+        }
+
+        @Override
+        public void updatePosition(int parentPositionX, int parentPositionY, boolean modified) {
+            if (isShowing() && getPositionListener().isOffsetVisible(getTextOffset())) {
+                updatePosition(parentPositionX, parentPositionY);
+            } else {
+                hide();
+            }
+        }
+
+        public boolean isShowing() {
+            return mPopupWindow.isShowing();
+        }
+    }
+
     private static class SuggestionRangeSpan extends UnderlineSpan {
         // TODO themable, would be nice to make it a child class of TextAppearanceSpan, but
         // there is no way to have underline and TextAppearanceSpan.
     }
 
-    private class SuggestionsPopupWindow implements OnClickListener {
+    private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnClickListener {
         private static final int MAX_NUMBER_SUGGESTIONS = 5;
         private static final int NO_SUGGESTIONS = -1;
-        private final PopupWindow mPopupWindow;
-        private LinearLayout mSuggestionsContainer;
         private WordIterator mSuggestionWordIterator;
         private TextAppearanceSpan[] mHighlightSpans = new TextAppearanceSpan[0];
 
-        public SuggestionsPopupWindow() {
+        @Override
+        protected void createPopupWindow() {
             mPopupWindow = new PopupWindow(TextView.this.mContext, null,
-                    com.android.internal.R.attr.textSuggestionsWindowStyle);
-            mPopupWindow.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
+                com.android.internal.R.attr.textSuggestionsWindowStyle);
             mPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
             mPopupWindow.setOutsideTouchable(true);
-            mPopupWindow.setClippingEnabled(true);
+            mPopupWindow.setClippingEnabled(false);
+        }
 
-            mPopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
-            mPopupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
-
-            mSuggestionsContainer = new LinearLayout(TextView.this.mContext);
-            mSuggestionsContainer.setOrientation(LinearLayout.VERTICAL);
+        @Override
+        protected void initContentView() {
+            mContentView.setOrientation(LinearLayout.VERTICAL);
 
             LayoutInflater inflater = (LayoutInflater) TextView.this.mContext.
                     getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -8793,7 +9024,7 @@
             // Inflate the suggestion items once and for all.
             for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) {
                 View childView = inflater.inflate(mTextEditSuggestionItemLayout,
-                        mSuggestionsContainer, false);
+                        mContentView, false);
 
                 if (! (childView instanceof TextView)) {
                     throw new IllegalArgumentException(
@@ -8801,11 +9032,9 @@
                 }
 
                 childView.setTag(new SuggestionInfo());
-                mSuggestionsContainer.addView(childView);
+                mContentView.addView(childView);
                 childView.setOnClickListener(this);
             }
-
-            mPopupWindow.setContentView(mSuggestionsContainer);
         }
 
         private class SuggestionInfo {
@@ -8825,30 +9054,61 @@
             SuggestionSpan[] suggestionSpans = spannable.getSpans(pos, pos, SuggestionSpan.class);
 
             // Cache the span length for performance reason.
-            final HashMap<SuggestionSpan, Integer> spanLengthMap =
-                new HashMap<SuggestionSpan, Integer>();
+            final HashMap<SuggestionSpan, Integer> spansLengths =
+                    new HashMap<SuggestionSpan, Integer>();
 
             for (SuggestionSpan suggestionSpan : suggestionSpans) {
                 int start = spannable.getSpanStart(suggestionSpan);
                 int end = spannable.getSpanEnd(suggestionSpan);
-                spanLengthMap.put(suggestionSpan, end - start);
+                spansLengths.put(suggestionSpan, Integer.valueOf(end - start));
             }
 
             // The suggestions are sorted according to the lenght of the text that they cover
             // (shorter first)
             Arrays.sort(suggestionSpans, new Comparator<SuggestionSpan>() {
                 public int compare(SuggestionSpan span1, SuggestionSpan span2) {
-                    return spanLengthMap.get(span1) - spanLengthMap.get(span2);
+                    return spansLengths.get(span1).intValue() - spansLengths.get(span2).intValue();
                 }
             });
 
             return suggestionSpans;
         }
 
+        @Override
         public void show() {
             if (!(mText instanceof Editable)) return;
+            updateSuggestions();
 
-            Spannable spannable = (Spannable) TextView.this.mText;
+            super.show();
+        }
+
+        @Override
+        protected int getTextOffset() {
+            return getSelectionStart();
+        }
+
+        @Override
+        protected int getVerticalLocalPosition(int line) {
+            return mLayout.getLineBottom(line);
+        }
+
+        @Override
+        protected int clipVertically(int positionY) {
+            final int height = mContentView.getMeasuredHeight();
+            final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+            return Math.min(positionY, displayMetrics.heightPixels - height);
+        }
+
+        @Override
+        public void hide() {
+            super.hide();
+            if ((mText instanceof Editable) && mSuggestionRangeSpan != null) {
+                ((Editable) mText).removeSpan(mSuggestionRangeSpan);
+            }
+        }
+
+        private void updateSuggestions() {
+            Spannable spannable = (Spannable)TextView.this.mText;
             SuggestionSpan[] suggestionSpans = getSuggestionSpans();
 
             final int nbSpans = suggestionSpans.length;
@@ -8867,7 +9127,7 @@
                 String[] suggestions = suggestionSpan.getSuggestions();
                 int nbSuggestions = suggestions.length;
                 for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) {
-                    TextView textView = (TextView) mSuggestionsContainer.getChildAt(
+                    TextView textView = (TextView) mContentView.getChildAt(
                             totalNbSuggestions);
                     textView.setText(suggestions[suggestionIndex]);
                     SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag();
@@ -8887,7 +9147,7 @@
 
             if (totalNbSuggestions == 0) {
                 // TODO Replace by final text, use a dedicated layout, add a fade out timer...
-                TextView textView = (TextView) mSuggestionsContainer.getChildAt(0);
+                TextView textView = (TextView) mContentView.getChildAt(0);
                 textView.setText("No suggestions available");
                 SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag();
                 suggestionInfo.spanStart = NO_SUGGESTIONS;
@@ -8898,26 +9158,17 @@
                         Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
 
                 for (int i = 0; i < totalNbSuggestions; i++) {
-                    final TextView textView = (TextView) mSuggestionsContainer.getChildAt(i);
+                    final TextView textView = (TextView) mContentView.getChildAt(i);
                     highlightTextDifferences(textView, spanUnionStart, spanUnionEnd);
                 }
             }
 
             for (int i = 0; i < totalNbSuggestions; i++) {
-                mSuggestionsContainer.getChildAt(i).setVisibility(VISIBLE);
+                mContentView.getChildAt(i).setVisibility(VISIBLE);
             }
             for (int i = totalNbSuggestions; i < MAX_NUMBER_SUGGESTIONS; i++) {
-                mSuggestionsContainer.getChildAt(i).setVisibility(GONE);
+                mContentView.getChildAt(i).setVisibility(GONE);
             }
-
-            final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
-            final int screenWidth = displayMetrics.widthPixels;
-            final int screenHeight = displayMetrics.heightPixels;
-            mSuggestionsContainer.measure(
-                    View.MeasureSpec.makeMeasureSpec(screenWidth, View.MeasureSpec.AT_MOST),
-                    View.MeasureSpec.makeMeasureSpec(screenHeight, View.MeasureSpec.AT_MOST));
-
-            positionAtCursor();
         }
 
         private long[] getWordLimits(CharSequence text) {
@@ -9069,17 +9320,6 @@
             textView.setText(ssb);
         }
 
-        public void hide() {
-            if ((mText instanceof Editable) && mSuggestionRangeSpan != null) {
-                ((Editable) mText).removeSpan(mSuggestionRangeSpan);
-            }
-            mPopupWindow.dismiss();
-        }
-
-        public boolean isShowing() {
-            return mPopupWindow.isShowing();
-        }
-
         @Override
         public void onClick(View view) {
             if (view instanceof TextView) {
@@ -9139,44 +9379,6 @@
             }
             hide();
         }
-
-        void positionAtCursor() {
-            View contentView = mPopupWindow.getContentView();
-            int width = contentView.getMeasuredWidth();
-            int height = contentView.getMeasuredHeight();
-            final int offset = TextView.this.getSelectionStart();
-            final int line = mLayout.getLineForOffset(offset);
-            final int lineBottom = mLayout.getLineBottom(line);
-            float primaryHorizontal = mLayout.getPrimaryHorizontal(offset);
-
-            final Rect bounds = sCursorControllerTempRect;
-            bounds.left = (int) (primaryHorizontal - width / 2.0f);
-            bounds.top = lineBottom;
-
-            bounds.right = bounds.left + width;
-            bounds.bottom = bounds.top + height;
-
-            convertFromViewportToContentCoordinates(bounds);
-
-            final int[] coords = mTempCoords;
-            TextView.this.getLocationInWindow(coords);
-            coords[0] += bounds.left;
-            coords[1] += bounds.top;
-
-            final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
-            final int screenHeight = displayMetrics.heightPixels;
-
-            // Vertical clipping
-            if (coords[1] + height > screenHeight) {
-                coords[1] = screenHeight - height;
-            }
-
-            // Horizontal clipping
-            coords[0] = Math.min(displayMetrics.widthPixels - width, coords[0]);
-            coords[0] = Math.max(0, coords[0]);
-
-            mPopupWindow.showAtLocation(TextView.this, Gravity.NO_GRAVITY, coords[0], coords[1]);
-        }
     }
 
     void showSuggestions() {
@@ -9357,7 +9559,7 @@
             boolean allowText = getContext().getResources().getBoolean(
                     com.android.internal.R.bool.config_allowActionMenuItemTextWithIcon);
 
-            mode.setTitle(allowText ? 
+            mode.setTitle(allowText ?
                     mContext.getString(com.android.internal.R.string.textSelectionCABTitle) : null);
             mode.setSubtitle(null);
 
@@ -9450,29 +9652,23 @@
         }
     }
 
-    private class ActionPopupWindow implements OnClickListener {
-        private static final int TEXT_EDIT_ACTION_POPUP_TEXT =
+    private class ActionPopupWindow extends PinnedPopupWindow implements OnClickListener {
+        private static final int POPUP_TEXT_LAYOUT =
                 com.android.internal.R.layout.text_edit_action_popup_text;
-        private final PopupWindow mPopupWindow;
         private TextView mPasteTextView;
         private TextView mReplaceTextView;
-        private LinearLayout mContentView;
         // Whether or not the Paste action should be available when the action popup is displayed
         private boolean mWithPaste;
 
-        public ActionPopupWindow() {
+        @Override
+        protected void createPopupWindow() {
             mPopupWindow = new PopupWindow(TextView.this.mContext, null,
                     com.android.internal.R.attr.textSelectHandleWindowStyle);
             mPopupWindow.setClippingEnabled(true);
-            mPopupWindow.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_PANEL);
+        }
 
-            mPopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
-            mPopupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
-
-            mContentView = new LinearLayout(TextView.this.getContext());
-            LayoutParams wrapContent = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
-                    ViewGroup.LayoutParams.WRAP_CONTENT);
-            mContentView.setLayoutParams(wrapContent);
+        @Override
+        protected void initContentView() {
             mContentView.setOrientation(LinearLayout.HORIZONTAL);
             mContentView.setBackgroundResource(
                     com.android.internal.R.drawable.text_edit_side_paste_window);
@@ -9480,36 +9676,26 @@
             LayoutInflater inflater = (LayoutInflater)TextView.this.mContext.
                     getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 
-            mPasteTextView = (TextView) inflater.inflate(TEXT_EDIT_ACTION_POPUP_TEXT, null);
+            LayoutParams wrapContent = new LayoutParams(
+                    ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+
+            mPasteTextView = (TextView) inflater.inflate(POPUP_TEXT_LAYOUT, null);
             mPasteTextView.setLayoutParams(wrapContent);
             mContentView.addView(mPasteTextView);
             mPasteTextView.setText(com.android.internal.R.string.paste);
             mPasteTextView.setOnClickListener(this);
 
-            mReplaceTextView = (TextView) inflater.inflate(TEXT_EDIT_ACTION_POPUP_TEXT, null);
+            mReplaceTextView = (TextView) inflater.inflate(POPUP_TEXT_LAYOUT, null);
             mReplaceTextView.setLayoutParams(wrapContent);
             mContentView.addView(mReplaceTextView);
             mReplaceTextView.setText(com.android.internal.R.string.replace);
             mReplaceTextView.setOnClickListener(this);
-
-            mPopupWindow.setContentView(mContentView);
         }
 
+        @Override
         public void show() {
             mPasteTextView.setVisibility(mWithPaste && canPaste() ? View.VISIBLE : View.GONE);
-
-            final int size = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-            mContentView.measure(size, size);
-
-            positionAtCursor();
-        }
-
-        public void hide() {
-            mPopupWindow.dismiss();
-        }
-
-        public boolean isShowing() {
-            return mPopupWindow.isShowing();
+            super.show();
         }
 
         @Override
@@ -9522,48 +9708,30 @@
             }
         }
 
-        void positionAtCursor() {
-            int width = mContentView.getMeasuredWidth();
-            int height = mContentView.getMeasuredHeight();
-            final int selectionStart = TextView.this.getSelectionStart();
-            final int selectionEnd = TextView.this.getSelectionEnd();
-            final int offset = (selectionStart + selectionEnd) / 2;
-            final int line = mLayout.getLineForOffset(offset);
-            final int lineTop = mLayout.getLineTop(line);
-            float primaryHorizontal = mLayout.getPrimaryHorizontal(offset);
+        @Override
+        protected int getTextOffset() {
+            return (getSelectionStart() + getSelectionEnd()) / 2;
+        }
 
-            final Rect bounds = sCursorControllerTempRect;
-            bounds.left = (int) (primaryHorizontal - width / 2.0f);
-            bounds.top = lineTop - height;
+        @Override
+        protected int getVerticalLocalPosition(int line) {
+            return mLayout.getLineTop(line) - mContentView.getMeasuredHeight();
+        }
 
-            bounds.right = bounds.left + width;
-            bounds.bottom = bounds.top + height;
-
-            convertFromViewportToContentCoordinates(bounds);
-
-            final int[] coords = mTempCoords;
-            TextView.this.getLocationInWindow(coords);
-            coords[0] += bounds.left;
-            coords[1] += bounds.top;
-
-            // Vertical clipping, move under edited line and to the side of insertion cursor
-            if (coords[1] < 0) {
-                coords[1] += height;
-                final int lineBottom = mLayout.getLineBottom(line);
-                final int lineHeight = lineBottom - lineTop;
-                coords[1] += lineHeight;
+        @Override
+        protected int clipVertically(int positionY) {
+            if (positionY < 0) {
+                final int offset = getTextOffset();
+                final int line = mLayout.getLineForOffset(offset);
+                positionY += mLayout.getLineBottom(line) - mLayout.getLineTop(line);
+                positionY += mContentView.getMeasuredHeight();
 
                 // Assumes insertion and selection handles share the same height
                 final Drawable handle = mContext.getResources().getDrawable(mTextSelectHandleRes);
-                coords[1] += handle.getIntrinsicHeight();
+                positionY += handle.getIntrinsicHeight();
             }
 
-            // Horizontal clipping
-            coords[0] = Math.max(0, coords[0]);
-            final int screenWidth = mContext.getResources().getDisplayMetrics().widthPixels;
-            coords[0] = Math.min(screenWidth - width, coords[0]);
-
-            mPopupWindow.showAtLocation(TextView.this, Gravity.NO_GRAVITY, coords[0], coords[1]);
+            return positionY;
         }
 
         public void setShowWithPaste(boolean withPaste) {
@@ -9571,7 +9739,7 @@
         }
     }
 
-    private abstract class HandleView extends View implements ViewTreeObserver.OnPreDrawListener {
+    private abstract class HandleView extends View implements TextViewPositionListener {
         protected Drawable mDrawable;
         private final PopupWindow mContainer;
         // Position with respect to the parent TextView
@@ -9579,21 +9747,19 @@
         private boolean mIsDragging;
         // Offset from touch position to mPosition
         private float mTouchToWindowOffsetX, mTouchToWindowOffsetY;
-        protected float mHotspotX;
+        protected int mHotspotX;
         // Offsets the hotspot point up, so that cursor is not hidden by the finger when moving up
         private float mTouchOffsetY;
         // Where the touch position should be on the handle to ensure a maximum cursor visibility
         private float mIdealVerticalOffset;
         // Parent's (TextView) previous position in window
         private int mLastParentX, mLastParentY;
-        // PopupWindow container absolute position with respect to the enclosing window
-        private int mContainerPositionX, mContainerPositionY;
-        // Visible or not (scrolled off screen), whether or not this handle should be visible
-        private boolean mIsActive = false;
-        // Used to detect that setFrame was called
-        private boolean mNeedsUpdate = true;
         // Transient action popup window for Paste and Replace actions
         protected ActionPopupWindow mActionPopupWindow;
+        // Previous text character offset
+        private int mPreviousOffset = -1;
+        // Previous text character offset
+        private boolean mPositionHasChanged = true;
         // Used to delay the appearance of the action popup window
         private Runnable mActionPopupShower;
 
@@ -9613,15 +9779,6 @@
             mIdealVerticalOffset = 0.7f * handleHeight;
         }
 
-        @Override
-        protected boolean setFrame(int left, int top, int right, int bottom) {
-            boolean changed = super.setFrame(left, top, right, bottom);
-            // onPreDraw is called for PhoneWindow before the layout of this view is
-            // performed. Make sure to update position, even if container didn't move.
-            if (changed) mNeedsUpdate  = true;
-            return changed;
-        }
-
         protected abstract void initDrawable();
 
         // Touch-up filter: number of previous positions remembered
@@ -9639,12 +9796,6 @@
         }
 
         private void addPositionToTouchUpFilter(int offset) {
-            if (mNumberPreviousOffsets > 0 &&
-                    mPreviousOffsets[mPreviousOffsetIndex] == offset) {
-                // Make sure only actual changes of position are recorded.
-                return;
-            }
-
             mPreviousOffsetIndex = (mPreviousOffsetIndex + 1) % HISTORY_SIZE;
             mPreviousOffsets[mPreviousOffsetIndex] = offset;
             mPreviousOffsetsTimes[mPreviousOffsetIndex] = SystemClock.uptimeMillis();
@@ -9663,28 +9814,28 @@
 
             if (i > 0 && i < iMax &&
                     (now - mPreviousOffsetsTimes[index]) > TOUCH_UP_FILTER_DELAY_BEFORE) {
-                updateOffset(mPreviousOffsets[index]);
+                positionAtCursorOffset(mPreviousOffsets[index]);
             }
         }
 
+        public boolean offsetHasBeenChanged() {
+            return mNumberPreviousOffsets > 1;
+        }
+
         @Override
         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
             setMeasuredDimension(mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight());
         }
 
         public void show() {
-            if (isShowing()) {
-                mContainer.update(mContainerPositionX, mContainerPositionY, -1, -1);
-            } else {
-                mContainer.showAtLocation(TextView.this, 0,
-                        mContainerPositionX, mContainerPositionY);
+            if (isShowing()) return;
 
-                if (!mIsActive) {
-                    ViewTreeObserver vto = TextView.this.getViewTreeObserver();
-                    vto.addOnPreDrawListener(this);
-                    mIsActive = true;
-                }
-            }
+            getPositionListener().addSubscriber(this, true);
+
+            // Make sure the offset is always considered new, even when focusing at same position
+            mPreviousOffset = -1;
+            positionAtCursorOffset(getCurrentCursorOffset());
+
             hideActionPopupWindow();
         }
 
@@ -9697,9 +9848,7 @@
         public void hide() {
             dismiss();
 
-            ViewTreeObserver vto = TextView.this.getViewTreeObserver();
-            vto.removeOnPreDrawListener(this);
-            mIsActive = false;
+            TextView.this.getPositionListener().removeSubscriber(this);
         }
 
         void showActionPopupWindow(int delay, boolean withPaste) {
@@ -9732,7 +9881,7 @@
             return mContainer.isShowing();
         }
 
-        private boolean isPositionVisible() {
+        private boolean isVisible() {
             // Always show a dragging handle.
             if (mIsDragging) {
                 return true;
@@ -9742,103 +9891,71 @@
                 return false;
             }
 
-            final int extendedPaddingTop = getExtendedPaddingTop();
-            final int extendedPaddingBottom = getExtendedPaddingBottom();
-            final int compoundPaddingLeft = getCompoundPaddingLeft();
-            final int compoundPaddingRight = getCompoundPaddingRight();
-
-            final TextView textView = TextView.this;
-
-            if (mTempRect == null) mTempRect = new Rect();
-            final Rect clip = mTempRect;
-            clip.left = compoundPaddingLeft;
-            clip.top = extendedPaddingTop;
-            clip.right = textView.getWidth() - compoundPaddingRight;
-            clip.bottom = textView.getHeight() - extendedPaddingBottom;
-
-            final ViewParent parent = textView.getParent();
-            if (parent == null || !parent.getChildVisibleRect(textView, clip, null)) {
-                return false;
-            }
-
-            final int[] coords = mTempCoords;
-            textView.getLocationInWindow(coords);
-            final int posX = coords[0] + mPositionX + (int) mHotspotX;
-            final int posY = coords[1] + mPositionY;
-
-            // Offset by 1 to take into account 0.5 and int rounding around getPrimaryHorizontal.
-            return posX >= clip.left - 1 && posX <= clip.right + 1 &&
-                    posY >= clip.top && posY <= clip.bottom;
+            return getPositionListener().isVisible(mPositionX + mHotspotX, mPositionY);
         }
 
         public abstract int getCurrentCursorOffset();
 
-        public abstract void updateOffset(int offset);
+        public abstract void updateSelection(int offset);
 
         public abstract void updatePosition(float x, float y);
 
         protected void positionAtCursorOffset(int offset) {
-            // A HandleView relies on the layout, which may be nulled by external methods.
+            // A HandleView relies on the layout, which may be nulled by external methods
             if (mLayout == null) {
                 // Will update controllers' state, hiding them and stopping selection mode if needed
                 prepareCursorControllers();
                 return;
             }
 
-            addPositionToTouchUpFilter(offset);
-            final int line = mLayout.getLineForOffset(offset);
-            final int lineBottom = mLayout.getLineBottom(line);
+            if (offset != mPreviousOffset) {
+                updateSelection(offset);
+                addPositionToTouchUpFilter(offset);
+                final int line = mLayout.getLineForOffset(offset);
 
-            mPositionX = (int) (mLayout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX);
-            mPositionY = lineBottom;
+                mPositionX = (int) (mLayout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX);
+                mPositionY = mLayout.getLineBottom(line);
 
-            // Take TextView's padding into account.
-            mPositionX += viewportToContentHorizontalOffset();
-            mPositionY += viewportToContentVerticalOffset();
+                // Take TextView's padding into account.
+                mPositionX += viewportToContentHorizontalOffset();
+                mPositionY += viewportToContentVerticalOffset();
+
+                mPreviousOffset = offset;
+                mPositionHasChanged = true;
+            }
         }
 
-        private void checkForContainerPositionChange() {
-            positionAtCursorOffset(getCurrentCursorOffset());
-
-            final int previousContainerPositionX = mContainerPositionX;
-            final int previousContainerPositionY = mContainerPositionY;
-
-            TextView.this.getLocationInWindow(mTempCoords);
-            mContainerPositionX = mTempCoords[0] + mPositionX;
-            mContainerPositionY = mTempCoords[1] + mPositionY;
-
-            mNeedsUpdate |= previousContainerPositionX != mContainerPositionX;
-            mNeedsUpdate |= previousContainerPositionY != mContainerPositionY;
-        }
-
-        public boolean onPreDraw() {
-            checkForContainerPositionChange();
-            if (mNeedsUpdate) {
+        public void updatePosition(int parentPositionX, int parentPositionY, boolean modified) {
+            if (modified || mPositionHasChanged) {
                 if (mIsDragging) {
-                    if (mTempCoords[0] != mLastParentX || mTempCoords[1] != mLastParentY) {
-                        mTouchToWindowOffsetX += mTempCoords[0] - mLastParentX;
-                        mTouchToWindowOffsetY += mTempCoords[1] - mLastParentY;
-                        mLastParentX = mTempCoords[0];
-                        mLastParentY = mTempCoords[1];
+                    // Update touchToWindow offset in case of parent scrolling while dragging
+                    if (parentPositionX != mLastParentX || parentPositionY != mLastParentY) {
+                        mTouchToWindowOffsetX += parentPositionX - mLastParentX;
+                        mTouchToWindowOffsetY += parentPositionY - mLastParentY;
+                        mLastParentX = parentPositionX;
+                        mLastParentY = parentPositionY;
                     }
 
                     onHandleMoved();
                 }
 
-                if (isPositionVisible()) {
-                    mContainer.update(mContainerPositionX, mContainerPositionY, -1, -1);
-
-                    if (mIsActive && !isShowing()) {
-                        show();
+                if (isVisible()) {
+                    final int positionX = parentPositionX + mPositionX;
+                    final int positionY = parentPositionY + mPositionY;
+                    if (isShowing()) {
+                        mContainer.update(positionX, positionY, -1, -1);
+                    } else {
+                        mContainer.showAtLocation(TextView.this, Gravity.NO_GRAVITY,
+                                positionX, positionY);
                     }
                 } else {
                     if (isShowing()) {
                         dismiss();
                     }
                 }
-                mNeedsUpdate = false;
+
+                mPositionHasChanged = false;
             }
-            return true;
         }
 
         @Override
@@ -9855,10 +9972,9 @@
                     mTouchToWindowOffsetX = ev.getRawX() - mPositionX;
                     mTouchToWindowOffsetY = ev.getRawY() - mPositionY;
 
-                    final int[] coords = mTempCoords;
-                    TextView.this.getLocationInWindow(coords);
-                    mLastParentX = coords[0];
-                    mLastParentY = coords[1];
+                    final PositionListener positionListener = getPositionListener();
+                    mLastParentX = positionListener.getPositionX();
+                    mLastParentY = positionListener.getPositionY();
                     mIsDragging = true;
                     break;
                 }
@@ -9961,7 +10077,7 @@
                         mTextSelectHandleRes);
             }
             mDrawable = mSelectHandleCenter;
-            mHotspotX = mDrawable.getIntrinsicWidth() / 2.0f;
+            mHotspotX = mDrawable.getIntrinsicWidth() / 2;
         }
 
         @Override
@@ -9975,15 +10091,17 @@
                     break;
 
                 case MotionEvent.ACTION_UP:
-                    final float deltaX = mDownPositionX - ev.getRawX();
-                    final float deltaY = mDownPositionY - ev.getRawY();
-                    final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
-                    if (distanceSquared < mSquaredTouchSlopDistance) {
-                        if (mActionPopupWindow != null && mActionPopupWindow.isShowing()) {
-                            // Tapping on the handle dismisses the displayed action popup
-                            mActionPopupWindow.hide();
-                        } else {
-                            show(0);
+                    if (!offsetHasBeenChanged()) {
+                        final float deltaX = mDownPositionX - ev.getRawX();
+                        final float deltaY = mDownPositionY - ev.getRawY();
+                        final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
+                        if (distanceSquared < mSquaredTouchSlopDistance) {
+                            if (mActionPopupWindow != null && mActionPopupWindow.isShowing()) {
+                                // Tapping on the handle dismisses the displayed action popup
+                                mActionPopupWindow.hide();
+                            } else {
+                                show(0);
+                            }
                         }
                     }
                     hideAfterDelay();
@@ -10006,13 +10124,13 @@
         }
 
         @Override
-        public void updateOffset(int offset) {
+        public void updateSelection(int offset) {
             Selection.setSelection((Spannable) mText, offset);
         }
 
         @Override
         public void updatePosition(float x, float y) {
-            updateOffset(getOffsetForPosition(x, y));
+            positionAtCursorOffset(getOffsetForPosition(x, y));
         }
 
         @Override
@@ -10036,7 +10154,7 @@
                         mTextSelectHandleLeftRes);
             }
             mDrawable = mSelectHandleLeft;
-            mHotspotX = mDrawable.getIntrinsicWidth() * 3.0f / 4.0f;
+            mHotspotX = (mDrawable.getIntrinsicWidth() * 3) / 4;
         }
 
         @Override
@@ -10045,7 +10163,7 @@
         }
 
         @Override
-        public void updateOffset(int offset) {
+        public void updateSelection(int offset) {
             Selection.setSelection((Spannable) mText, offset, getSelectionEnd());
         }
 
@@ -10061,7 +10179,7 @@
             // Handles can not cross and selection is at least one character
             if (offset >= selectionEnd) offset = selectionEnd - 1;
 
-            Selection.setSelection((Spannable) mText, offset, selectionEnd);
+            positionAtCursorOffset(offset);
         }
 
         public ActionPopupWindow getActionPopupWindow() {
@@ -10077,7 +10195,7 @@
                         mTextSelectHandleRightRes);
             }
             mDrawable = mSelectHandleRight;
-            mHotspotX = mDrawable.getIntrinsicWidth() / 4.0f;
+            mHotspotX = mDrawable.getIntrinsicWidth() / 4;
         }
 
         @Override
@@ -10086,7 +10204,7 @@
         }
 
         @Override
-        public void updateOffset(int offset) {
+        public void updateSelection(int offset) {
             Selection.setSelection((Spannable) mText, getSelectionStart(), offset);
         }
 
@@ -10102,7 +10220,7 @@
             // Handles can not cross and selection is at least one character
             if (offset <= selectionStart) offset = selectionStart + 1;
 
-            Selection.setSelection((Spannable) mText, selectionStart, offset);
+            positionAtCursorOffset(offset);
         }
 
         public void setActionPopupWindow(ActionPopupWindow actionPopupWindow) {
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 1531946..6d65782 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package com.android.internal.content;
 
 import android.os.Build;
@@ -17,6 +33,12 @@
 
     private static native long nativeSumNativeBinaries(String file, String cpuAbi, String cpuAbi2);
 
+    /**
+     * Sums the size of native binaries in an APK.
+     *
+     * @param apkFile APK file to scan for native libraries
+     * @return size of all native binary files in bytes
+     */
     public static long sumNativeBinariesLI(File apkFile) {
         final String cpuAbi = Build.CPU_ABI;
         final String cpuAbi2 = Build.CPU_ABI2;
@@ -26,6 +48,14 @@
     private native static int nativeCopyNativeBinaries(String filePath, String sharedLibraryPath,
             String cpuAbi, String cpuAbi2);
 
+    /**
+     * Copies native binaries to a shared library directory.
+     *
+     * @param apkFile APK file to scan for native libraries
+     * @param sharedLibraryDir directory for libraries to be copied to
+     * @return {@link PackageManager#INSTALL_SUCCEEDED} if successful or another
+     *         error code from that class if not
+     */
     public static int copyNativeBinariesIfNeededLI(File apkFile, File sharedLibraryDir) {
         final String cpuAbi = Build.CPU_ABI;
         final String cpuAbi2 = Build.CPU_ABI2;
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index ec64552..266728b 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -39,6 +39,8 @@
     public static final int RECOMMEND_FAILED_INVALID_LOCATION = -3;
     public static final int RECOMMEND_FAILED_ALREADY_EXISTS = -4;
     public static final int RECOMMEND_MEDIA_UNAVAILABLE = -5;
+    public static final int RECOMMEND_FAILED_INVALID_URI = -6;
+
     private static final boolean localLOGV = true;
     private static final String TAG = "PackageHelper";
     // App installation location settings values
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index d36be10..d61a579 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -32,7 +32,7 @@
  */
 public class VpnConfig implements Parcelable {
 
-    public static final String ACTION_VPN_REVOKED = "android.net.vpn.action.REVOKED";
+    public static final String SERVICE_INTERFACE = "android.net.VpnService";
 
     public static final String LEGACY_VPN = "[Legacy VPN]";
 
@@ -52,7 +52,7 @@
                 PendingIntent.FLAG_NO_CREATE : PendingIntent.FLAG_CANCEL_CURRENT);
     }
 
-    public String packagz;
+    public String user;
     public String interfaze;
     public String session;
     public int mtu = -1;
@@ -70,7 +70,7 @@
 
     @Override
     public void writeToParcel(Parcel out, int flags) {
-        out.writeString(packagz);
+        out.writeString(user);
         out.writeString(interfaze);
         out.writeString(session);
         out.writeInt(mtu);
@@ -87,7 +87,7 @@
         @Override
         public VpnConfig createFromParcel(Parcel in) {
             VpnConfig config = new VpnConfig();
-            config.packagz = in.readString();
+            config.user = in.readString();
             config.interfaze = in.readString();
             config.session = in.readString();
             config.mtu = in.readInt();
diff --git a/core/java/com/android/internal/textservice/ISpellCheckerService.aidl b/core/java/com/android/internal/textservice/ISpellCheckerService.aidl
index ff00492..67d7b3e 100644
--- a/core/java/com/android/internal/textservice/ISpellCheckerService.aidl
+++ b/core/java/com/android/internal/textservice/ISpellCheckerService.aidl
@@ -19,11 +19,13 @@
 import com.android.internal.textservice.ISpellCheckerSession;
 import com.android.internal.textservice.ISpellCheckerSessionListener;
 
+import android.os.Bundle;
+
 /**
  * Public interface to the global spell checker.
  * @hide
  */
 interface ISpellCheckerService {
     ISpellCheckerSession getISpellCheckerSession(
-            String locale, ISpellCheckerSessionListener listener);
+            String locale, ISpellCheckerSessionListener listener, in Bundle bundle);
 }
diff --git a/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl b/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl
index 79e43510c0..5a00603 100644
--- a/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl
+++ b/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl
@@ -22,7 +22,7 @@
  * @hide
  */
 oneway interface ISpellCheckerSession {
-    void getSuggestionsMultiple(
+    void onGetSuggestionsMultiple(
             in TextInfo[] textInfos, int suggestionsLimit, boolean multipleWords);
-    void cancel();
+    void onCancel();
 }
diff --git a/core/java/com/android/internal/textservice/ITextServicesManager.aidl b/core/java/com/android/internal/textservice/ITextServicesManager.aidl
index 4d7dfbb..bb4b2a3 100644
--- a/core/java/com/android/internal/textservice/ITextServicesManager.aidl
+++ b/core/java/com/android/internal/textservice/ITextServicesManager.aidl
@@ -20,6 +20,7 @@
 import com.android.internal.textservice.ITextServicesSessionListener;
 
 import android.content.ComponentName;
+import android.os.Bundle;
 import android.view.textservice.SpellCheckerInfo;
 
 /**
@@ -30,7 +31,7 @@
     SpellCheckerInfo getCurrentSpellChecker(String locale);
     oneway void getSpellCheckerService(String sciId, in String locale,
             in ITextServicesSessionListener tsListener,
-            in ISpellCheckerSessionListener scListener);
+            in ISpellCheckerSessionListener scListener, in Bundle bundle);
     oneway void finishSpellCheckerService(in ISpellCheckerSessionListener listener);
     oneway void setCurrentSpellChecker(String sciId);
     SpellCheckerInfo[] getEnabledSpellCheckers();
diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
new file mode 100644
index 0000000..850e1f0
--- /dev/null
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -0,0 +1,110 @@
+/*
+ * 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.util;
+
+import java.io.FileInputStream;
+
+import android.os.StrictMode;
+
+public class MemInfoReader {
+    byte[] mBuffer = new byte[1024];
+
+    private long mTotalSize;
+    private long mFreeSize;
+    private long mCachedSize;
+
+    private boolean matchText(byte[] buffer, int index, String text) {
+        int N = text.length();
+        if ((index+N) >= buffer.length) {
+            return false;
+        }
+        for (int i=0; i<N; i++) {
+            if (buffer[index+i] != text.charAt(i)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private long extractMemValue(byte[] buffer, int index) {
+        while (index < buffer.length && buffer[index] != '\n') {
+            if (buffer[index] >= '0' && buffer[index] <= '9') {
+                int start = index;
+                index++;
+                while (index < buffer.length && buffer[index] >= '0'
+                    && buffer[index] <= '9') {
+                    index++;
+                }
+                String str = new String(buffer, 0, start, index-start);
+                return ((long)Integer.parseInt(str)) * 1024;
+            }
+            index++;
+        }
+        return 0;
+    }
+
+    public void readMemInfo() {
+        // Permit disk reads here, as /proc/meminfo isn't really "on
+        // disk" and should be fast.  TODO: make BlockGuard ignore
+        // /proc/ and /sys/ files perhaps?
+        StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
+        try {
+            mTotalSize = 0;
+            mFreeSize = 0;
+            mCachedSize = 0;
+            FileInputStream is = new FileInputStream("/proc/meminfo");
+            int len = is.read(mBuffer);
+            is.close();
+            final int BUFLEN = mBuffer.length;
+            int count = 0;
+            for (int i=0; i<len && count < 3; i++) {
+                if (matchText(mBuffer, i, "MemTotal")) {
+                    i += 8;
+                    mTotalSize = extractMemValue(mBuffer, i);
+                    count++;
+                } else if (matchText(mBuffer, i, "MemFree")) {
+                    i += 7;
+                    mFreeSize = extractMemValue(mBuffer, i);
+                    count++;
+                } else if (matchText(mBuffer, i, "Cached")) {
+                    i += 6;
+                    mCachedSize = extractMemValue(mBuffer, i);
+                    count++;
+                }
+                while (i < BUFLEN && mBuffer[i] != '\n') {
+                    i++;
+                }
+            }
+        } catch (java.io.FileNotFoundException e) {
+        } catch (java.io.IOException e) {
+        } finally {
+            StrictMode.setThreadPolicy(savedPolicy);
+        }
+    }
+
+    public long getTotalSize() {
+        return mTotalSize;
+    }
+
+    public long getFreeSize() {
+        return mFreeSize;
+    }
+
+    public long getCachedSize() {
+        return mCachedSize;
+    }
+}
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index 9ecd29f..0cadb16 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -49,5 +49,6 @@
     public static final int BASE_DATA_CONNECTION_AC                                 = 0x00041000;
     public static final int BASE_DATA_CONNECTION_TRACKER                            = 0x00042000;
 
+    public static final int BASE_DNS_PINGER                                         = 0x00050000;
     //TODO: define all used protocols
 }
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index cbe72dd..36f0246 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -1226,6 +1226,12 @@
      * be executed and upon the next message arriving
      * destState.enter will be invoked.
      *
+     * this function can also be called inside the enter function of the
+     * previous transition target, but the behavior is undefined when it is
+     * called mid-way through a previous transition (for example, calling this
+     * in the enter() routine of a intermediate node when the current transition
+     * target is one of the nodes descendants).
+     *
      * @param destState will be the state that receives the next message.
      */
     protected final void transitionTo(IState destState) {
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 7839a08..5e70e4c 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -150,6 +150,11 @@
 
     private CopyOnWriteArrayList<WeakReference<MenuPresenter>> mPresenters =
             new CopyOnWriteArrayList<WeakReference<MenuPresenter>>();
+
+    /**
+     * Currently expanded menu item; must be collapsed when we clear.
+     */
+    private MenuItemImpl mExpandedItem;
     
     /**
      * Called by menu to notify of close and selection changes.
@@ -512,6 +517,9 @@
     }
     
     public void clear() {
+        if (mExpandedItem != null) {
+            collapseItemActionView(mExpandedItem);
+        }
         mItems.clear();
         
         onItemsChanged(true);
@@ -1223,11 +1231,14 @@
         }
         startDispatchingItemsChanged();
 
+        if (expanded) {
+            mExpandedItem = item;
+        }
         return expanded;
     }
 
     public boolean collapseItemActionView(MenuItemImpl item) {
-        if (mPresenters.isEmpty()) return false;
+        if (mPresenters.isEmpty() || mExpandedItem != item) return false;
 
         boolean collapsed = false;
 
@@ -1242,6 +1253,9 @@
         }
         startDispatchingItemsChanged();
 
+        if (collapsed) {
+            mExpandedItem = null;
+        }
         return collapsed;
     }
 }
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 446c842..61df5c7 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -583,7 +583,7 @@
     }
 
     public void setLogo(int resId) {
-        mContext.getResources().getDrawable(resId);
+        setLogo(mContext.getResources().getDrawable(resId));
     }
 
     /**
@@ -1265,9 +1265,8 @@
         @Override
         public void initForMenu(Context context, MenuBuilder menu) {
             // Clear the expanded action view when menus change.
-            mExpandedActionView = null;
-            if (mCurrentExpandedItem != null) {
-                mCurrentExpandedItem.collapseActionView();
+            if (mMenu != null && mCurrentExpandedItem != null) {
+                mMenu.collapseItemActionView(mCurrentExpandedItem);
             }
             mMenu = menu;
         }
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
index fb33748..366b983 100644
--- a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
@@ -29,6 +29,7 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.ViewRootImpl;
 import com.android.internal.R;
 
@@ -62,7 +63,8 @@
         mContext = context;
         mTargetView = targetView;
         mKeyboardView = keyboardView;
-        if (useFullScreenWidth || mKeyboardView.getLayoutParams().width == -1) {
+        if (useFullScreenWidth
+                || mKeyboardView.getLayoutParams().width == ViewGroup.LayoutParams.MATCH_PARENT) {
             createKeyboards();
         } else {
             createKeyboardsWithSpecificSize(mKeyboardView.getLayoutParams().width,
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index 0510023..ec926e4 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -127,6 +127,7 @@
             mAnimatingTargets = false;
         }
     };
+    private int mTargetResourceId;
 
     public MultiWaveView(Context context) {
         this(context, null);
@@ -474,6 +475,7 @@
             Drawable drawable = array.getDrawable(i);
             targetDrawables.add(new TargetDrawable(res, drawable));
         }
+        mTargetResourceId = resourceId;
         mTargetDrawables = targetDrawables;
         updateTargetPositions();
     }
@@ -492,6 +494,10 @@
         }
     }
 
+    public int getTargetResourceId() {
+        return mTargetResourceId;
+    }
+
     /**
      * Enable or disable vibrate on touch.
      *
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 6e73889..170957c 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -178,6 +178,7 @@
 	external/icu4c/i18n \
 	external/icu4c/common \
 	external/jpeg \
+	external/harfbuzz/contrib \
 	external/harfbuzz/src \
 	external/zlib \
 	frameworks/opt/emoji \
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 2de0932..ffcd1a0 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -233,6 +233,12 @@
     return surfaceTexture->getTimestamp();
 }
 
+static void SurfaceTexture_release(JNIEnv* env, jobject thiz)
+{
+    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+    surfaceTexture->abandon();
+}
+
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gSurfaceTextureMethods[] = {
@@ -243,6 +249,7 @@
     {"nativeUpdateTexImage",     "()V",   (void*)SurfaceTexture_updateTexImage },
     {"nativeGetTransformMatrix", "([F)V", (void*)SurfaceTexture_getTransformMatrix },
     {"nativeGetTimestamp",       "()J",   (void*)SurfaceTexture_getTimestamp },
+    {"nativeRelease",            "()V",   (void*)SurfaceTexture_release },
 };
 
 int register_android_graphics_SurfaceTexture(JNIEnv* env)
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 30fe298..a29eb38 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -17,6 +17,10 @@
 #include "TextLayoutCache.h"
 #include "TextLayout.h"
 
+extern "C" {
+#include "harfbuzz-unicode.h"
+}
+
 namespace android {
 
 TextLayoutCache::TextLayoutCache() :
@@ -355,7 +359,9 @@
     shaperItem->item.pos = start;
     shaperItem->item.length = count;
     shaperItem->item.bidiLevel = isRTL;
-    shaperItem->item.script = isRTL ? HB_Script_Arabic : HB_Script_Common;
+
+    ssize_t iter = 0;
+    shaperItem->item.script = code_point_to_script(utf16_to_code_point(chars, count, &iter));
 
     shaperItem->string = chars;
     shaperItem->stringLength = contextCount;
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 3a3f07e..85fac5f 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -279,6 +279,39 @@
     android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object);
 }
 
+static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid)
+{
+    char line[1024];
+    jlong pss = 0;
+    unsigned temp;
+
+    char tmp[128];
+    FILE *fp;
+
+    sprintf(tmp, "/proc/%d/smaps", pid);
+    fp = fopen(tmp, "r");
+    if (fp == 0) return 0;
+
+    while (true) {
+        if (fgets(line, 1024, fp) == 0) {
+            break;
+        }
+
+        if (sscanf(line, "Pss: %d kB", &temp) == 1) {
+            pss += temp;
+        }
+    }
+
+    fclose(fp);
+
+    return pss;
+}
+
+static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz)
+{
+    return android_os_Debug_getPssPid(env, clazz, getpid());
+}
+
 static jint read_binder_stat(const char* stat)
 {
     FILE* fp = fopen(BINDER_STATS, "r");
@@ -520,6 +553,10 @@
             (void*) android_os_Debug_getDirtyPages },
     { "getMemoryInfo",          "(ILandroid/os/Debug$MemoryInfo;)V",
             (void*) android_os_Debug_getDirtyPagesPid },
+    { "getPss",                 "()J",
+            (void*) android_os_Debug_getPss },
+    { "getPss",                 "(I)J",
+            (void*) android_os_Debug_getPssPid },
     { "dumpNativeHeap",         "(Ljava/io/FileDescriptor;)V",
             (void*) android_os_Debug_dumpNativeHeap },
     { "getBinderSentTransactions", "()I",
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index 830f70e..5118351 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -51,15 +51,17 @@
 
 namespace android {
 
-typedef void (*iterFunc)(JNIEnv*, void*, ZipFileRO*, ZipEntryRO, const char*);
-
 // These match PackageManager.java install codes
 typedef enum {
-    INSTALL_SUCCEEDED = 0,
+    INSTALL_SUCCEEDED = 1,
     INSTALL_FAILED_INVALID_APK = -2,
     INSTALL_FAILED_INSUFFICIENT_STORAGE = -4,
+    INSTALL_FAILED_CONTAINER_ERROR = -18,
+    INSTALL_FAILED_INTERNAL_ERROR = -110,
 } install_status_t;
 
+typedef install_status_t (*iterFunc)(JNIEnv*, void*, ZipFileRO*, ZipEntryRO, const char*);
+
 // Equivalent to isFilenameSafe
 static bool
 isFilenameSafe(const char* filename)
@@ -140,17 +142,19 @@
     return false;
 }
 
-static void
+static install_status_t
 sumFiles(JNIEnv* env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char* fileName)
 {
     size_t* total = (size_t*) arg;
     size_t uncompLen;
 
     if (!zipFile->getEntryInfo(zipEntry, NULL, &uncompLen, NULL, NULL, NULL, NULL)) {
-        return;
+        return INSTALL_FAILED_INVALID_APK;
     }
 
     *total += uncompLen;
+
+    return INSTALL_SUCCEEDED;
 }
 
 /*
@@ -158,7 +162,7 @@
  *
  * This function assumes the library and path names passed in are considered safe.
  */
-static void
+static install_status_t
 copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char* fileName)
 {
     jstring* javaNativeLibPath = (jstring*) arg;
@@ -170,7 +174,8 @@
     time_t modTime;
 
     if (!zipFile->getEntryInfo(zipEntry, NULL, &uncompLen, NULL, NULL, &when, &crc)) {
-        return;
+        LOGD("Couldn't read zip entry info\n");
+        return INSTALL_FAILED_INVALID_APK;
     } else {
         struct tm t;
         ZipFileRO::zipTimeToTimespec(when, &t);
@@ -182,50 +187,50 @@
     char localFileName[nativeLibPath.size() + fileNameLen + 2];
 
     if (strlcpy(localFileName, nativeLibPath.c_str(), sizeof(localFileName)) != nativeLibPath.size()) {
-        LOGD("Couldn't allocate local file name for library: %s", strerror(errno));
-        return;
+        LOGD("Couldn't allocate local file name for library");
+        return INSTALL_FAILED_INTERNAL_ERROR;
     }
 
     *(localFileName + nativeLibPath.size()) = '/';
 
     if (strlcpy(localFileName + nativeLibPath.size() + 1, fileName, sizeof(localFileName)
                     - nativeLibPath.size() - 1) != fileNameLen) {
-        LOGD("Couldn't allocate local file name for library: %s", strerror(errno));
-        return;
+        LOGD("Couldn't allocate local file name for library");
+        return INSTALL_FAILED_INTERNAL_ERROR;
     }
 
     // Only copy out the native file if it's different.
     struct stat st;
     if (!isFileDifferent(localFileName, uncompLen, modTime, crc, &st)) {
-        return;
+        return INSTALL_SUCCEEDED;
     }
 
     char localTmpFileName[nativeLibPath.size() + TMP_FILE_PATTERN_LEN + 2];
     if (strlcpy(localTmpFileName, nativeLibPath.c_str(), sizeof(localTmpFileName))
             != nativeLibPath.size()) {
-        LOGD("Couldn't allocate local file name for library: %s", strerror(errno));
-        return;
+        LOGD("Couldn't allocate local file name for library");
+        return INSTALL_FAILED_INTERNAL_ERROR;
     }
 
     *(localFileName + nativeLibPath.size()) = '/';
 
     if (strlcpy(localTmpFileName + nativeLibPath.size(), TMP_FILE_PATTERN,
                     TMP_FILE_PATTERN_LEN - nativeLibPath.size()) != TMP_FILE_PATTERN_LEN) {
-        LOGI("Couldn't allocate temporary file name for library: %s", strerror(errno));
-        return;
+        LOGI("Couldn't allocate temporary file name for library");
+        return INSTALL_FAILED_INTERNAL_ERROR;
     }
 
     int fd = mkstemp(localTmpFileName);
     if (fd < 0) {
         LOGI("Couldn't open temporary file name: %s: %s\n", localTmpFileName, strerror(errno));
-        return;
+        return INSTALL_FAILED_CONTAINER_ERROR;
     }
 
     if (!zipFile->uncompressEntry(zipEntry, fd)) {
-        LOGI("Failed uncompressing %s to %s: %s", fileName, localTmpFileName, strerror(errno));
+        LOGI("Failed uncompressing %s to %s\n", fileName, localTmpFileName);
         close(fd);
         unlink(localTmpFileName);
-        return;
+        return INSTALL_FAILED_CONTAINER_ERROR;
     }
 
     close(fd);
@@ -238,7 +243,7 @@
     if (utimes(localTmpFileName, times) < 0) {
         LOGI("Couldn't change modification time on %s: %s\n", localTmpFileName, strerror(errno));
         unlink(localTmpFileName);
-        return;
+        return INSTALL_FAILED_CONTAINER_ERROR;
     }
 
     // Set the mode to 755
@@ -246,17 +251,19 @@
     if (chmod(localTmpFileName, mode) < 0) {
         LOGI("Couldn't change permissions on %s: %s\n", localTmpFileName, strerror(errno));
         unlink(localTmpFileName);
-        return;
+        return INSTALL_FAILED_CONTAINER_ERROR;
     }
 
     // Finally, rename it to the final name.
     if (rename(localTmpFileName, localFileName) < 0) {
         LOGI("Couldn't rename %s to %s: %s\n", localTmpFileName, localFileName, strerror(errno));
         unlink(localTmpFileName);
-        return;
+        return INSTALL_FAILED_CONTAINER_ERROR;
     }
 
     LOGV("Successfully moved %s to %s\n", localTmpFileName, localFileName);
+
+    return INSTALL_SUCCEEDED;
 }
 
 static install_status_t
@@ -301,10 +308,7 @@
         }
 
         const char* lastSlash = strrchr(fileName, '/');
-        if (lastSlash == NULL) {
-            LOG_ASSERT("last slash was null somehow for %s\n", fileName);
-            continue;
-        }
+        LOG_ASSERT(lastSlash != NULL, "last slash was null somehow for %s\n", fileName);
 
         // Check to make sure the CPU ABI of this file is one we support.
         const char* cpuAbiOffset = fileName + APK_LIB_LEN;
@@ -325,12 +329,17 @@
         }
 
         // If this is a .so file, check to see if we need to copy it.
-        if (!strncmp(fileName + fileNameLen - LIB_SUFFIX_LEN, LIB_SUFFIX, LIB_SUFFIX_LEN)
-                && !strncmp(lastSlash, LIB_PREFIX, LIB_PREFIX_LEN)
-                && isFilenameSafe(lastSlash + 1)) {
-            callFunc(env, callArg, &zipFile, entry, lastSlash + 1);
-        } else if (!strncmp(lastSlash + 1, GDBSERVER, GDBSERVER_LEN)) {
-            callFunc(env, callArg, &zipFile, entry, lastSlash + 1);
+        if ((!strncmp(fileName + fileNameLen - LIB_SUFFIX_LEN, LIB_SUFFIX, LIB_SUFFIX_LEN)
+                    && !strncmp(lastSlash, LIB_PREFIX, LIB_PREFIX_LEN)
+                    && isFilenameSafe(lastSlash + 1))
+                || !strncmp(lastSlash + 1, GDBSERVER, GDBSERVER_LEN)) {
+
+            install_status_t ret = callFunc(env, callArg, &zipFile, entry, lastSlash + 1);
+
+            if (ret != INSTALL_SUCCEEDED) {
+                LOGV("Failure for entry %s", lastSlash + 1);
+                return ret;
+            }
         }
     }
 
@@ -341,7 +350,7 @@
 com_android_internal_content_NativeLibraryHelper_copyNativeBinaries(JNIEnv *env, jclass clazz,
         jstring javaFilePath, jstring javaNativeLibPath, jstring javaCpuAbi, jstring javaCpuAbi2)
 {
-    return iterateOverNativeFiles(env, javaFilePath, javaCpuAbi, javaCpuAbi2,
+    return (jint) iterateOverNativeFiles(env, javaFilePath, javaCpuAbi, javaCpuAbi2,
             copyFileIfChanged, &javaNativeLibPath);
 }
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f99a94c..57b686a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -63,7 +63,7 @@
     <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" />
     <protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" />
     <protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" />
-    
+
     <protected-broadcast android:name="android.backup.intent.RUN" />
     <protected-broadcast android:name="android.backup.intent.CLEAR" />
     <protected-broadcast android:name="android.backup.intent.INIT" />
@@ -292,13 +292,12 @@
         android:description="@string/permdesc_setAlarm"
         android:protectionLevel="normal" />
 
-   <!-- Allows an application to read/write the voicemails owned by its own
-        package. -->
-    <permission android:name="com.android.voicemail.permission.READ_WRITE_OWN_VOICEMAIL"
+   <!-- Allows an application to add voicemails into the system. -->
+    <permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL"
         android:permissionGroup="android.permission-group.PERSONAL_INFO"
         android:protectionLevel="dangerous"
-        android:label="@string/permlab_readWriteOwnVoicemail"
-        android:description="@string/permdesc_readWriteOwnVoicemail" />
+        android:label="@string/permlab_addVoicemail"
+        android:description="@string/permdesc_addVoicemail" />
 
     <!-- ======================================= -->
     <!-- Permissions for accessing location info -->
@@ -393,14 +392,6 @@
         android:description="@string/permdesc_nfc"
         android:label="@string/permlab_nfc" />
 
-    <!-- Allows applications to provide VPN functionality.
-         @hide Pending API council approval -->
-    <permission android:name="android.permission.VPN"
-        android:permissionGroup="android.permission-group.NETWORK"
-        android:protectionLevel="dangerous"
-        android:description="@string/permdesc_vpn"
-        android:label="@string/permlab_vpn" />
-
     <!-- Allows an application to use SIP service -->
     <permission android:name="android.permission.USE_SIP"
         android:permissionGroup="android.permission-group.NETWORK"
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_dark_normal_holo.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_dark_normal_holo.9.png
new file mode 100644
index 0000000..5e6a9d6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_dark_normal_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_dark_normal_off_holo.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_dark_normal_off_holo.9.png
new file mode 100644
index 0000000..eb9d740
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_dark_normal_off_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_holo.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_holo.9.png
new file mode 100644
index 0000000..869a330
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_dark_pressed_holo.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_dark_pressed_holo.9.png
new file mode 100644
index 0000000..7ec33dd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_dark_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_holo.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
new file mode 100644
index 0000000..72d63da
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_holo.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
new file mode 100644
index 0000000..fcc5cac
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_light_normal_holo.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_light_normal_holo.9.png
new file mode 100644
index 0000000..baff858
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_light_normal_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_light_pressed_holo.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_light_pressed_holo.9.png
new file mode 100644
index 0000000..5612c51
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_light_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_camera_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_camera_activated.png
new file mode 100644
index 0000000..d510e1d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_camera_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_camera_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_camera_normal.png
new file mode 100644
index 0000000..36d766d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_camera_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.png
index fce4980..d1938b9 100644
--- a/core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.png
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.png
index 73f01c9..f6ccbd2 100644
--- a/core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.png
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png
index d01bdb2..10b3268 100644
--- a/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.png
index d333946..d1f3015 100644
--- a/core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.png
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_activated_holo_dark.9.png b/core/res/res/drawable-hdpi/spinner_ab_activated_holo_dark.9.png
new file mode 100644
index 0000000..d471c30
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_ab_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_activated_holo_light.9.png b/core/res/res/drawable-hdpi/spinner_ab_activated_holo_light.9.png
new file mode 100644
index 0000000..d471c30
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_ab_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_default_holo_dark.9.png b/core/res/res/drawable-hdpi/spinner_ab_default_holo_dark.9.png
new file mode 100644
index 0000000..001cfbb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_ab_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_default_holo_light.9.png b/core/res/res/drawable-hdpi/spinner_ab_default_holo_light.9.png
new file mode 100644
index 0000000..5e278c8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_ab_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/spinner_ab_disabled_holo_dark.9.png
new file mode 100644
index 0000000..cf2e149
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_ab_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/spinner_ab_disabled_holo_light.9.png
new file mode 100644
index 0000000..63f212d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_ab_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/spinner_ab_focused_holo_dark.9.png
new file mode 100644
index 0000000..85663e6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_ab_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_focused_holo_light.9.png b/core/res/res/drawable-hdpi/spinner_ab_focused_holo_light.9.png
new file mode 100644
index 0000000..85663e6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_ab_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark.9.png
new file mode 100644
index 0000000..afddbe8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light.9.png
new file mode 100644
index 0000000..0ad6476
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_cab_active_holo_dark.9.png b/core/res/res/drawable-hdpi/spinner_cab_active_holo_dark.9.png
deleted file mode 100644
index 7cad0c9..0000000
--- a/core/res/res/drawable-hdpi/spinner_cab_active_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_cab_active_holo_light.9.png b/core/res/res/drawable-hdpi/spinner_cab_active_holo_light.9.png
deleted file mode 100644
index 7cad0c9..0000000
--- a/core/res/res/drawable-hdpi/spinner_cab_active_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_cab_default_holo_dark.9.png b/core/res/res/drawable-hdpi/spinner_cab_default_holo_dark.9.png
deleted file mode 100644
index b3f3cf7..0000000
--- a/core/res/res/drawable-hdpi/spinner_cab_default_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_cab_default_holo_light.9.png b/core/res/res/drawable-hdpi/spinner_cab_default_holo_light.9.png
deleted file mode 100644
index af46631..0000000
--- a/core/res/res/drawable-hdpi/spinner_cab_default_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_cab_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/spinner_cab_disabled_holo_dark.9.png
deleted file mode 100644
index e672c95..0000000
--- a/core/res/res/drawable-hdpi/spinner_cab_disabled_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_cab_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/spinner_cab_disabled_holo_light.9.png
deleted file mode 100644
index f499540..0000000
--- a/core/res/res/drawable-hdpi/spinner_cab_disabled_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_cab_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/spinner_cab_focused_holo_dark.9.png
deleted file mode 100644
index f4900a5..0000000
--- a/core/res/res/drawable-hdpi/spinner_cab_focused_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_cab_focused_holo_light.9.png b/core/res/res/drawable-hdpi/spinner_cab_focused_holo_light.9.png
deleted file mode 100644
index 1286542..0000000
--- a/core/res/res/drawable-hdpi/spinner_cab_focused_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_cab_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/spinner_cab_pressed_holo_dark.9.png
deleted file mode 100644
index 8b6f9dd..0000000
--- a/core/res/res/drawable-hdpi/spinner_cab_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_cab_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/spinner_cab_pressed_holo_light.9.png
deleted file mode 100644
index 4f0c476..0000000
--- a/core/res/res/drawable-hdpi/spinner_cab_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_default_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_search_default_holo_dark.9.png
index 62e3274..288b809 100644
--- a/core/res/res/drawable-hdpi/textfield_search_default_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_default_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_search_default_holo_light.9.png
index b7512fa..7866e06 100644
--- a/core/res/res/drawable-hdpi/textfield_search_default_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_right_default_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_search_right_default_holo_dark.9.png
index bfc6f83..699552d 100644
--- a/core/res/res/drawable-hdpi/textfield_search_right_default_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_right_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_right_default_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_search_right_default_holo_light.9.png
index 708ba90..543afa2 100644
--- a/core/res/res/drawable-hdpi/textfield_search_right_default_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_right_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_dark.9.png
index 0da1e9c..e1a5e70 100644
--- a/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_light.9.png
index 2e93557..e79e95b 100644
--- a/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_selected_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_search_selected_holo_dark.9.png
index 7aeaad6..8a5d810 100644
--- a/core/res/res/drawable-hdpi/textfield_search_selected_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_selected_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_search_selected_holo_light.9.png
index cf46f32..177b631 100644
--- a/core/res/res/drawable-hdpi/textfield_search_selected_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_keyboard_key_dark_normal_holo.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_dark_normal_holo.9.png
new file mode 100644
index 0000000..d449d76
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_dark_normal_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_keyboard_key_dark_normal_off_holo.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_dark_normal_off_holo.9.png
new file mode 100644
index 0000000..80fe863
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_dark_normal_off_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_holo.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_holo.9.png
new file mode 100644
index 0000000..196d6d9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_keyboard_key_dark_pressed_holo.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_dark_pressed_holo.9.png
new file mode 100644
index 0000000..8f340d3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_dark_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_holo.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
new file mode 100644
index 0000000..b34b957
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_holo.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
new file mode 100644
index 0000000..02f4b3d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_keyboard_key_light_normal_holo.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_light_normal_holo.9.png
new file mode 100644
index 0000000..976083f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_light_normal_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_keyboard_key_light_pressed_holo.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_light_pressed_holo.9.png
new file mode 100644
index 0000000..c39dd4a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_light_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_camera_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_camera_activated.png
new file mode 100644
index 0000000..1437798
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_camera_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_camera_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_camera_normal.png
new file mode 100644
index 0000000..b718258
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_camera_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.png
index 3b2f3fc..2bc3f52 100644
--- a/core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.png
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.png
index 03f524d..637eec6 100644
--- a/core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.png
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png
index dbfc5ba..878ff1f 100644
--- a/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.png
index df47993..0d3f756 100644
--- a/core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.png
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_activated_holo_dark.9.png b/core/res/res/drawable-mdpi/spinner_ab_activated_holo_dark.9.png
new file mode 100644
index 0000000..34c9188
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_ab_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_activated_holo_light.9.png b/core/res/res/drawable-mdpi/spinner_ab_activated_holo_light.9.png
new file mode 100644
index 0000000..34c9188
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_ab_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_default_holo_dark.9.png b/core/res/res/drawable-mdpi/spinner_ab_default_holo_dark.9.png
new file mode 100644
index 0000000..b92abaf
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_ab_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_default_holo_light.9.png b/core/res/res/drawable-mdpi/spinner_ab_default_holo_light.9.png
new file mode 100644
index 0000000..91f0e87
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_ab_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/spinner_ab_disabled_holo_dark.9.png
new file mode 100644
index 0000000..dab7eda
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_ab_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/spinner_ab_disabled_holo_light.9.png
new file mode 100644
index 0000000..bf14605
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_ab_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/spinner_ab_focused_holo_dark.9.png
new file mode 100644
index 0000000..c733260
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_ab_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_focused_holo_light.9.png b/core/res/res/drawable-mdpi/spinner_ab_focused_holo_light.9.png
new file mode 100644
index 0000000..c733260
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_ab_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark.9.png
new file mode 100644
index 0000000..6d290a6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light.9.png
new file mode 100644
index 0000000..6dae484
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_cab_active_holo_dark.9.png b/core/res/res/drawable-mdpi/spinner_cab_active_holo_dark.9.png
deleted file mode 100644
index 617c379..0000000
--- a/core/res/res/drawable-mdpi/spinner_cab_active_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_cab_active_holo_light.9.png b/core/res/res/drawable-mdpi/spinner_cab_active_holo_light.9.png
deleted file mode 100644
index 617c379..0000000
--- a/core/res/res/drawable-mdpi/spinner_cab_active_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_cab_default_holo_dark.9.png b/core/res/res/drawable-mdpi/spinner_cab_default_holo_dark.9.png
deleted file mode 100644
index d76b123..0000000
--- a/core/res/res/drawable-mdpi/spinner_cab_default_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_cab_default_holo_light.9.png b/core/res/res/drawable-mdpi/spinner_cab_default_holo_light.9.png
deleted file mode 100644
index ee91044..0000000
--- a/core/res/res/drawable-mdpi/spinner_cab_default_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_cab_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/spinner_cab_disabled_holo_dark.9.png
deleted file mode 100644
index fc9c109..0000000
--- a/core/res/res/drawable-mdpi/spinner_cab_disabled_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_cab_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/spinner_cab_disabled_holo_light.9.png
deleted file mode 100644
index 7fc7cc1..0000000
--- a/core/res/res/drawable-mdpi/spinner_cab_disabled_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_cab_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/spinner_cab_focused_holo_dark.9.png
deleted file mode 100644
index 0f49fe9..0000000
--- a/core/res/res/drawable-mdpi/spinner_cab_focused_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_cab_focused_holo_light.9.png b/core/res/res/drawable-mdpi/spinner_cab_focused_holo_light.9.png
deleted file mode 100644
index 032d5d3..0000000
--- a/core/res/res/drawable-mdpi/spinner_cab_focused_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_cab_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/spinner_cab_pressed_holo_dark.9.png
deleted file mode 100644
index df0a935..0000000
--- a/core/res/res/drawable-mdpi/spinner_cab_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_cab_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/spinner_cab_pressed_holo_light.9.png
deleted file mode 100644
index b43177b..0000000
--- a/core/res/res/drawable-mdpi/spinner_cab_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_default_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_search_default_holo_dark.9.png
index 62e3274..faaa6c2 100644
--- a/core/res/res/drawable-mdpi/textfield_search_default_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_default_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_search_default_holo_light.9.png
index b7512fa..ec44405 100644
--- a/core/res/res/drawable-mdpi/textfield_search_default_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_right_default_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_search_right_default_holo_dark.9.png
index bfc6f83..1cc76a3 100644
--- a/core/res/res/drawable-mdpi/textfield_search_right_default_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_right_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_right_default_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_search_right_default_holo_light.9.png
index 708ba90..2593760 100644
--- a/core/res/res/drawable-mdpi/textfield_search_right_default_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_right_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_dark.9.png
index 0da1e9c..8688d6a 100644
--- a/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_light.9.png
index 2e93557..3f4c282 100644
--- a/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_selected_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_search_selected_holo_dark.9.png
index 7aeaad6..8692528 100644
--- a/core/res/res/drawable-mdpi/textfield_search_selected_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_selected_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_search_selected_holo_light.9.png
index cf46f32..849af73 100644
--- a/core/res/res/drawable-mdpi/textfield_search_selected_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_keyboard_key_dark_normal_holo.9.png b/core/res/res/drawable-xhdpi/btn_keyboard_key_dark_normal_holo.9.png
new file mode 100644
index 0000000..d2cd029
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_keyboard_key_dark_normal_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_keyboard_key_dark_normal_off_holo.9.png b/core/res/res/drawable-xhdpi/btn_keyboard_key_dark_normal_off_holo.9.png
new file mode 100644
index 0000000..0f709eb
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_keyboard_key_dark_normal_off_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_keyboard_key_dark_normal_on_holo.9.png b/core/res/res/drawable-xhdpi/btn_keyboard_key_dark_normal_on_holo.9.png
new file mode 100644
index 0000000..2f4de8e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_keyboard_key_dark_normal_on_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_holo.9.png b/core/res/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_holo.9.png
new file mode 100644
index 0000000..3871689e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_off_holo.9.png b/core/res/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
new file mode 100644
index 0000000..836ea6e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on_holo.9.png b/core/res/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
new file mode 100644
index 0000000..279db1f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_keyboard_key_light_normal_holo.9.png b/core/res/res/drawable-xhdpi/btn_keyboard_key_light_normal_holo.9.png
new file mode 100644
index 0000000..b26f1d2
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_keyboard_key_light_normal_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_keyboard_key_light_pressed_holo.9.png b/core/res/res/drawable-xhdpi/btn_keyboard_key_light_pressed_holo.9.png
new file mode 100644
index 0000000..c23a4b2
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_keyboard_key_light_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_camera_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_camera_activated.png
new file mode 100644
index 0000000..d545883
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_camera_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_camera_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_camera_normal.png
new file mode 100644
index 0000000..8de7b84
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_camera_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.png
index fd81211..2900045 100644
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.png
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png
index 9edc70b..da2adc2 100644
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png
index 29c4572..ddebe3e 100644
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png
index fa0be96..73d7af3 100644
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_activated_holo_dark.9.png b/core/res/res/drawable-xhdpi/spinner_ab_activated_holo_dark.9.png
new file mode 100644
index 0000000..85d8540
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_ab_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_activated_holo_light.9.png b/core/res/res/drawable-xhdpi/spinner_ab_activated_holo_light.9.png
new file mode 100644
index 0000000..85d8540
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_ab_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_default_holo_dark.9.png b/core/res/res/drawable-xhdpi/spinner_ab_default_holo_dark.9.png
new file mode 100644
index 0000000..31b39d7
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_ab_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_default_holo_light.9.png b/core/res/res/drawable-xhdpi/spinner_ab_default_holo_light.9.png
new file mode 100644
index 0000000..1527c5c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_ab_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_disabled_holo_dark.9.png b/core/res/res/drawable-xhdpi/spinner_ab_disabled_holo_dark.9.png
new file mode 100644
index 0000000..e4cef9a
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_ab_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_disabled_holo_light.9.png b/core/res/res/drawable-xhdpi/spinner_ab_disabled_holo_light.9.png
new file mode 100644
index 0000000..1c37ece
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_ab_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_focused_holo_dark.9.png b/core/res/res/drawable-xhdpi/spinner_ab_focused_holo_dark.9.png
new file mode 100644
index 0000000..6aae46b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_ab_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_focused_holo_light.9.png b/core/res/res/drawable-xhdpi/spinner_ab_focused_holo_light.9.png
new file mode 100644
index 0000000..6aae46b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_ab_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark.9.png
new file mode 100644
index 0000000..db2e034
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light.9.png
new file mode 100644
index 0000000..77bb433
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_search_default_holo_dark.9.png b/core/res/res/drawable-xhdpi/textfield_search_default_holo_dark.9.png
new file mode 100644
index 0000000..1a1a9c4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/textfield_search_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_search_default_holo_light.9.png b/core/res/res/drawable-xhdpi/textfield_search_default_holo_light.9.png
new file mode 100644
index 0000000..462cea6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/textfield_search_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_search_right_default_holo_dark.9.png b/core/res/res/drawable-xhdpi/textfield_search_right_default_holo_dark.9.png
new file mode 100644
index 0000000..3e178b2
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/textfield_search_right_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_search_right_default_holo_light.9.png b/core/res/res/drawable-xhdpi/textfield_search_right_default_holo_light.9.png
new file mode 100644
index 0000000..4c34b93
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/textfield_search_right_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_search_right_selected_holo_dark.9.png b/core/res/res/drawable-xhdpi/textfield_search_right_selected_holo_dark.9.png
new file mode 100644
index 0000000..cf1b3ca
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/textfield_search_right_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_search_right_selected_holo_light.9.png b/core/res/res/drawable-xhdpi/textfield_search_right_selected_holo_light.9.png
new file mode 100644
index 0000000..0ee383b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/textfield_search_right_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_search_selected_holo_dark.9.png b/core/res/res/drawable-xhdpi/textfield_search_selected_holo_dark.9.png
new file mode 100644
index 0000000..42c019e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/textfield_search_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_search_selected_holo_light.9.png b/core/res/res/drawable-xhdpi/textfield_search_selected_holo_light.9.png
new file mode 100644
index 0000000..63efe71
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/textfield_search_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_ics.xml b/core/res/res/drawable/btn_keyboard_key_ics.xml
new file mode 100644
index 0000000..7335cc2
--- /dev/null
+++ b/core/res/res/drawable/btn_keyboard_key_ics.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!-- Functional keys. -->
+
+    <item android:state_single="true" android:state_pressed="true"
+          android:drawable="@drawable/btn_keyboard_key_dark_pressed_holo" />
+    <item android:state_single="true"
+          android:drawable="@drawable/btn_keyboard_key_dark_normal_holo" />
+
+    <!-- Toggle keys. Use checkable/checked state. -->
+
+    <item android:state_checkable="true" android:state_checked="true" android:state_pressed="true"
+          android:drawable="@drawable/btn_keyboard_key_dark_pressed_on_holo" />
+    <item android:state_checkable="true" android:state_pressed="true"
+          android:drawable="@drawable/btn_keyboard_key_dark_pressed_off_holo" />
+    <item android:state_checkable="true" android:state_checked="true"
+          android:drawable="@drawable/btn_keyboard_key_dark_normal_on_holo" />
+    <item android:state_checkable="true"
+          android:drawable="@drawable/btn_keyboard_key_dark_normal_off_holo" />
+
+    <!-- Normal keys -->
+
+    <item android:state_pressed="true"
+          android:drawable="@drawable/btn_keyboard_key_light_pressed_holo" />
+    <item android:drawable="@drawable/btn_keyboard_key_light_normal_holo" />
+</selector>
diff --git a/core/res/res/drawable/ic_lockscreen_camera.xml b/core/res/res/drawable/ic_lockscreen_camera.xml
new file mode 100644
index 0000000..0e3ef37
--- /dev/null
+++ b/core/res/res/drawable/ic_lockscreen_camera.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:state_enabled="true"
+        android:state_active="false"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_lockscreen_camera_normal" />
+
+    <item
+        android:state_enabled="true"
+        android:state_active="true"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_lockscreen_camera_activated" />
+
+</selector>
diff --git a/core/res/res/drawable/spinner_cab_background_holo_dark.xml b/core/res/res/drawable/spinner_ab_holo_dark.xml
similarity index 66%
rename from core/res/res/drawable/spinner_cab_background_holo_dark.xml
rename to core/res/res/drawable/spinner_ab_holo_dark.xml
index 5572450..708b6ab 100644
--- a/core/res/res/drawable/spinner_cab_background_holo_dark.xml
+++ b/core/res/res/drawable/spinner_ab_holo_dark.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
+<!-- Copyright (C) 2011 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -16,10 +16,12 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
-          android:drawable="@drawable/spinner_cab_disabled_holo_dark" />
+          android:drawable="@drawable/spinner_ab_disabled_holo_dark" />
     <item android:state_pressed="true"
-          android:drawable="@drawable/spinner_cab_pressed_holo_dark" />
+          android:drawable="@drawable/spinner_ab_pressed_holo_dark" />
     <item android:state_pressed="false" android:state_focused="true"
-          android:drawable="@drawable/spinner_cab_focused_holo_dark" />
-    <item android:drawable="@drawable/spinner_cab_default_holo_dark" />
+          android:drawable="@drawable/spinner_ab_focused_holo_dark" />
+    <item android:state_activated="true"
+          android:drawable="@drawable/spinner_ab_activated_holo_dark" />
+    <item android:drawable="@drawable/spinner_ab_default_holo_dark" />
 </selector>
diff --git a/core/res/res/drawable/spinner_cab_background_holo_light.xml b/core/res/res/drawable/spinner_ab_holo_light.xml
similarity index 70%
rename from core/res/res/drawable/spinner_cab_background_holo_light.xml
rename to core/res/res/drawable/spinner_ab_holo_light.xml
index 98ff48d..c4901ca 100644
--- a/core/res/res/drawable/spinner_cab_background_holo_light.xml
+++ b/core/res/res/drawable/spinner_ab_holo_light.xml
@@ -16,10 +16,12 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
-          android:drawable="@drawable/spinner_cab_disabled_holo_light" />
+          android:drawable="@drawable/spinner_ab_disabled_holo_light" />
     <item android:state_pressed="true"
-          android:drawable="@drawable/spinner_cab_pressed_holo_light" />
+          android:drawable="@drawable/spinner_ab_pressed_holo_light" />
     <item android:state_pressed="false" android:state_focused="true"
-          android:drawable="@drawable/spinner_cab_focused_holo_light" />
-    <item android:drawable="@drawable/spinner_cab_default_holo_light" />
+          android:drawable="@drawable/spinner_ab_focused_holo_light" />
+    <item android:state_activated="true"
+          android:drawable="@drawable/spinner_ab_activated_holo_light" />
+    <item android:drawable="@drawable/spinner_ab_default_holo_light" />
 </selector>
diff --git a/core/res/res/layout/expanded_menu_layout.xml b/core/res/res/layout/expanded_menu_layout.xml
index 5d98773..f44a83f 100644
--- a/core/res/res/layout/expanded_menu_layout.xml
+++ b/core/res/res/layout/expanded_menu_layout.xml
@@ -16,5 +16,5 @@
 
 <com.android.internal.view.menu.ExpandedMenuView xmlns:android="http://schemas.android.com/apk/res/android"
 	android:id="@+android:id/expanded_menu" 
-	android:layout_width="296dip"
+	android:layout_width="?android:attr/panelMenuListWidth"
 	android:layout_height="wrap_content" />
diff --git a/core/res/res/layout/keyguard_screen_password_landscape.xml b/core/res/res/layout/keyguard_screen_password_landscape.xml
index 960907d..452b982 100644
--- a/core/res/res/layout/keyguard_screen_password_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_password_landscape.xml
@@ -24,15 +24,17 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical"
-    android:rowCount="7"
+    android:rowCount="8"
     android:id="@+id/root"
-    android:clipChildren="false">
+    android:clipChildren="false"
+    android:rowOrderPreserved="false">
 
     <!-- Column 0 -->
     <com.android.internal.widget.DigitalClock android:id="@+id/time"
         android:layout_marginTop="8dip"
         android:layout_marginBottom="8dip"
-        android:layout_gravity="right">
+        android:layout_gravity="right"
+        android:layout_rowSpan="2">
 
        <!-- Because we can't have multi-tone fonts, we render two TextViews, one on
         top of the other. Hence the redundant layout... -->
@@ -118,48 +120,52 @@
     />
 
     <!-- Column 1 -->
-    <Space android:layout_width="32dip" android:layout_rowSpan="7" />
+    <Space
+        android:layout_width="16dip"
+        android:layout_rowSpan="8"
+        android:layout_gravity="fill_vertical" />
 
     <!-- Column 2 - password entry field and PIN keyboard -->
     <LinearLayout
         android:orientation="vertical"
-        android:layout_gravity="center|fill"
-        android:layout_rowSpan="7">
+        android:layout_width="270dip"
+        android:layout_gravity="center_vertical">
 
         <EditText android:id="@+id/passwordEntry"
             android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
+            android:layout_width="match_parent"
+            android:gravity="center"
             android:singleLine="true"
             android:textStyle="normal"
             android:inputType="textPassword"
-            android:layout_gravity="center"
             android:textSize="24sp"
             android:minEms="8"
             android:textAppearance="?android:attr/textAppearanceMedium"
             android:background="@drawable/lockscreen_password_field_dark"
             android:textColor="?android:attr/textColorPrimary"
-            android:imeOptions="flagNoFullscreen"
+            android:imeOptions="flagNoFullscreen|actionDone"
             />
 
-        <!-- Numeric keyboard -->
-        <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
-            android:layout_width="250dip"
-            android:layout_height="100dip"
-            android:layout_gravity="center"
-            android:background="#40000000"
-            android:layout_marginTop="5dip"
-            android:keyBackground="@drawable/btn_keyboard_key_fulltrans"
-            android:visibility="gone"
-        />
-
     </LinearLayout>
 
+    <!-- Numeric keyboard -->
+    <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
+        android:layout_width="270dip"
+        android:layout_height="wrap_content"
+        android:layout_marginRight="4dip"
+        android:background="#40000000"
+        android:layout_marginTop="5dip"
+        android:keyBackground="@*android:drawable/btn_keyboard_key_ics"
+        android:visibility="gone"
+        android:layout_rowSpan="7"
+    />
+
     <!-- Music transport control -->
     <include android:id="@+id/transport"
         layout="@layout/keyguard_transport_control"
         android:layout_row="0"
         android:layout_column="0"
-        android:layout_rowSpan="5"
+        android:layout_rowSpan="6"
         android:layout_columnSpan="1"
         android:layout_gravity="fill"
         />
diff --git a/core/res/res/layout/keyguard_screen_password_portrait.xml b/core/res/res/layout/keyguard_screen_password_portrait.xml
index 7a51035..cd33275 100644
--- a/core/res/res/layout/keyguard_screen_password_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_password_portrait.xml
@@ -94,31 +94,32 @@
         android:drawablePadding="4dip"
         />
 
-    <Space android:layout_height="100dip"/>
-
     <!-- Password entry field -->
     <EditText android:id="@+id/passwordEntry"
         android:layout_height="wrap_content"
         android:layout_width="match_parent"
+        android:layout_gravity="center_vertical|fill_horizontal"
+        android:gravity="center_horizontal"
         android:singleLine="true"
         android:textStyle="normal"
         android:inputType="textPassword"
-        android:gravity="center"
-        android:textSize="22sp"
+        android:textSize="36sp"
         android:layout_marginLeft="16dip"
         android:layout_marginRight="16dip"
         android:background="@drawable/lockscreen_password_field_dark"
         android:textAppearance="?android:attr/textAppearanceMedium"
-        android:textColor="#ffffffff"/>
-
-    <Space android:layout_gravity="fill" />
+        android:textColor="#ffffffff"
+        android:imeOptions="actionDone"/>
 
     <!-- Numeric keyboard -->
     <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
         android:layout_width="match_parent"
-        android:layout_height="260dip"
+        android:layout_height="wrap_content"
+        android:layout_marginRight="4dip"
+        android:paddingTop="4dip"
+        android:paddingBottom="4dip"
         android:background="#40000000"
-        android:keyBackground="@*android:drawable/btn_keyboard_key_fulltrans"
+        android:keyBackground="@*android:drawable/btn_keyboard_key_ics"
         android:visibility="gone"
     />
 
@@ -139,7 +140,6 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginTop="4dip"
-        android:layout_marginRight="16dip"
         android:layout_gravity="center_horizontal"
         android:drawableLeft="@*android:drawable/lockscreen_emergency_button"
         style="?android:attr/buttonBarButtonStyle"
@@ -153,7 +153,7 @@
         layout="@layout/keyguard_transport_control"
         android:layout_row="0"
         android:layout_column="0"
-        android:layout_rowSpan="4"
+        android:layout_rowSpan="3"
         android:layout_columnSpan="1"
         android:layout_gravity="fill"
         />
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml
index 05c768d..6016d4e 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml
@@ -129,7 +129,7 @@
             android:layout_height="match_parent"
             android:layout_alignParentBottom="true"
 
-            android:targetDrawables="@array/lockscreen_targets_when_silent"
+            android:targetDrawables="@array/lockscreen_targets_with_camera"
             android:handleDrawable="@drawable/ic_lockscreen_handle"
             android:waveDrawable="@drawable/ic_lockscreen_outerring"
             android:outerRadius="@dimen/multiwaveview_target_placement_radius"
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
index 6440726..168bd1a 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
@@ -131,7 +131,7 @@
         android:layout_height="match_parent"
         android:layout_rowSpan="7"
 
-        android:targetDrawables="@array/lockscreen_targets_when_silent"
+        android:targetDrawables="@array/lockscreen_targets_with_camera"
         android:handleDrawable="@drawable/ic_lockscreen_handle"
         android:waveDrawable="@drawable/ic_lockscreen_outerring"
         android:outerRadius="@dimen/multiwaveview_target_placement_radius"
diff --git a/core/res/res/layout/list_menu_item_layout.xml b/core/res/res/layout/list_menu_item_layout.xml
index 57091a1..aaff4c7 100644
--- a/core/res/res/layout/list_menu_item_layout.xml
+++ b/core/res/res/layout/list_menu_item_layout.xml
@@ -16,7 +16,7 @@
 
 <com.android.internal.view.menu.ListMenuItemView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="?android:attr/listPreferredItemHeight">
+    android:layout_height="?android:attr/listPreferredItemHeightSmall">
     
     <!-- Icon will be inserted here. -->
     
diff --git a/core/res/res/values-land/arrays.xml b/core/res/res/values-land/arrays.xml
index 92d5a87..fd492ec 100644
--- a/core/res/res/values-land/arrays.xml
+++ b/core/res/res/values-land/arrays.xml
@@ -34,4 +34,11 @@
         <item>@drawable/ic_lockscreen_silent</item>
     </array>
 
+    <array name="lockscreen_targets_with_camera">
+        <item>@null</item>
+        <item>@drawable/ic_lockscreen_unlock</item>
+        <item>@null</item>
+        <item>@drawable/ic_lockscreen_camera</item>
+    </array>
+
 </resources>
diff --git a/core/res/res/values-land/dimens.xml b/core/res/res/values-land/dimens.xml
index 388eb38..02bb3c8 100644
--- a/core/res/res/values-land/dimens.xml
+++ b/core/res/res/values-land/dimens.xml
@@ -22,7 +22,7 @@
     <!-- Default height of a key in the password keyboard for alpha -->
     <dimen name="password_keyboard_key_height_alpha">47dip</dimen>
     <!-- Default height of a key in the password keyboard for numeric -->
-    <dimen name="password_keyboard_key_height_numeric">60dip</dimen>
+    <dimen name="password_keyboard_key_height_numeric">50dip</dimen>
     <!-- Default correction for the space key in the password keyboard -->
     <dimen name="password_keyboard_spacebar_vertical_correction">2dip</dimen>
     <dimen name="preference_widget_width">72dp</dimen>
diff --git a/core/res/res/values-large/themes.xml b/core/res/res/values-large/themes.xml
index 9e3e0bb..871a131 100644
--- a/core/res/res/values-large/themes.xml
+++ b/core/res/res/values-large/themes.xml
@@ -16,6 +16,21 @@
 ** limitations under the License.
 */
 -->
+
+<!--
+===============================================================
+                        PLEASE READ
+===============================================================
+
+The Holo themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see themes_device_defaults.xml.
+
+===============================================================
+                        PLEASE READ
+===============================================================
+ -->
 <resources>
     <style name="Theme.Holo.DialogWhenLarge"
             parent="@android:style/Theme.Holo.Dialog.MinWidth">
diff --git a/core/res/res/values-large/themes_device_defaults.xml b/core/res/res/values-large/themes_device_defaults.xml
new file mode 100644
index 0000000..52fff5c
--- /dev/null
+++ b/core/res/res/values-large/themes_device_defaults.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+
+<!--
+===============================================================
+                        PLEASE READ
+===============================================================
+This file contains the themes that are the Device Defaults.
+If you want to edit themes to skin your device, do it here.
+We recommend that you do not edit themes.xml and instead edit
+this file.
+
+Editing this file instead of themes.xml will greatly simplify
+merges for future platform versions and CTS compliance will be
+easier.
+===============================================================
+                        PLEASE READ
+===============================================================
+ -->
+<resources>
+    <style name="Theme.DeviceDefault.DialogWhenLarge"
+            parent="@android:style/Theme.DeviceDefault.Dialog.MinWidth">
+        <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+    </style>
+    <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar"
+            parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar.MinWidth">
+        <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+    </style>
+    <style name="Theme.DeviceDefault.Light.DialogWhenLarge"
+            parent="@android:style/Theme.DeviceDefault.Light.Dialog.MinWidth">
+    </style>
+    <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar"
+            parent="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth">
+    </style>
+</resources>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 73103a6..753e4ac 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -217,14 +217,18 @@
        <item>@drawable/scrollbar_handle_vertical</item>
        <item>@drawable/spinner_background_holo_dark</item>
        <item>@drawable/spinner_background_holo_light</item>
-       <item>@drawable/spinner_cab_default_holo_dark</item>
-       <item>@drawable/spinner_cab_default_holo_light</item>
-       <item>@drawable/spinner_cab_disabled_holo_dark</item>
-       <item>@drawable/spinner_cab_disabled_holo_light</item>
-       <item>@drawable/spinner_cab_focused_holo_dark</item>
-       <item>@drawable/spinner_cab_focused_holo_light</item>
-       <item>@drawable/spinner_cab_pressed_holo_dark</item>
-       <item>@drawable/spinner_cab_pressed_holo_light</item>
+       <item>@drawable/spinner_ab_default_holo_dark</item>
+       <item>@drawable/spinner_ab_default_holo_light</item>
+       <item>@drawable/spinner_ab_disabled_holo_dark</item>
+       <item>@drawable/spinner_ab_disabled_holo_light</item>
+       <item>@drawable/spinner_ab_focused_holo_dark</item>
+       <item>@drawable/spinner_ab_focused_holo_light</item>
+       <item>@drawable/spinner_ab_pressed_holo_dark</item>
+       <item>@drawable/spinner_ab_pressed_holo_light</item>
+       <item>@drawable/spinner_ab_activated_holo_dark</item>
+       <item>@drawable/spinner_ab_activated_holo_light</item>
+       <item>@drawable/spinner_ab_holo_dark</item>
+       <item>@drawable/spinner_ab_holo_light</item>
        <item>@drawable/spinner_default_holo_dark</item>
        <item>@drawable/spinner_default_holo_light</item>
        <item>@drawable/spinner_disabled_holo_dark</item>
@@ -358,4 +362,11 @@
         <item>@null</item>"
     </array>
 
+    <array name="lockscreen_targets_with_camera">
+        <item>@drawable/ic_lockscreen_unlock</item>
+        <item>@null</item>
+        <item>@drawable/ic_lockscreen_camera</item>
+        <item>@null</item>"
+    </array>
+
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index f70319b..63b49bd 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -439,6 +439,10 @@
         <!-- Default appearance of panel text. -->
         <attr name="panelTextAppearance" format="reference" />
 
+        <attr name="panelMenuIsCompact" format="boolean" />
+        <attr name="panelMenuListWidth" format="dimension" />
+        <attr name="panelMenuListTheme" format="reference" />
+
         <!-- =================== -->
         <!-- Other widget styles -->
         <!-- =================== -->
@@ -2220,6 +2224,34 @@
         <attr name="imeSubtypeExtraValue" format="string" />
     </declare-styleable>
 
+    <!-- Use <code>spell-checker</code> as the root tag of the XML resource that
+         describes an
+         {@link android.service.textservice.SpellCheckerService} service, which is
+         referenced from its
+         {@link android.view.textservice.SpellCheckerSession#SERVICE_META_DATA}
+         meta-data entry.  Described here are the attributes that can be
+         included in that tag. -->
+    <declare-styleable name="SpellChecker">
+        <!-- The name of the spell checker. -->
+        <attr name="label" />
+        <!-- Component name of an activity that allows the user to modify
+             the settings for this service. -->
+        <attr name="settingsActivity"/>
+    </declare-styleable>
+
+    <!-- This is the subtype of the spell checker. Subtype can describe locales (e.g. en_US, fr_FR...) -->
+    <declare-styleable name="SpellChecker_Subtype">
+        <!-- The name of the subtype. -->
+        <attr name="label" />
+        <!-- The locale of the subtype. This string should be a locale (e.g. en_US, fr_FR...)
+             This is also used by the framework to know the supported locales
+             of the spell checker.  -->
+        <attr name="subtypeLocale" format="string" />
+        <!-- The extra value of the subtype. This string can be any string and will be passed to
+             the SpellChecker.  -->
+        <attr name="subtypeExtraValue" format="string" />
+    </declare-styleable>
+
     <!-- Use <code>accessibility-service</code> as the root tag of the XML resource that
          describes an {@link android.accessibilityservice.AccessibilityService} service,
          which is referenced from its
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index dd16bd0..847afa0 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -710,6 +710,22 @@
         <enum name="preferExternal" value="2" />
     </attr>
 
+    <!-- Extra options for an activity's UI. If specified on the application
+         tag these will be considered defaults for all activities in the
+         application. -->
+    <attr name="uiOptions">
+        <!-- No extra UI options. -->
+        <flag name="none" value="0" />
+        <!-- Split the options menu into a separate bar at the bottom of
+             the screen when severely constrained for horizontal space.
+             (e.g. portrait mode on a phone.) Instead of a small number
+             of action buttons appearing in the action bar at the top
+             of the screen, the action bar will split into the top navigation
+             section and the bottom menu section. Menu items will not be
+             split across the two bars; they will always appear together. -->
+        <flag name="splitActionBarWhenNarrow" value="1" />
+    </attr>
+
     <!-- The <code>manifest</code> tag is the root of an
          <code>AndroidManifest.xml</code> file,
          describing the contents of an Android package (.apk) file.  One
@@ -812,6 +828,7 @@
              application is running, the user will be informed of this.
              @hide -->
         <attr name="cantSaveState" format="boolean" />
+        <attr name="uiOptions" />
     </declare-styleable>
     
     <!-- The <code>permission</code> tag declares a security permission that can be
@@ -1302,6 +1319,7 @@
         <attr name="windowSoftInputMode" />
         <attr name="immersive" />
         <attr name="hardwareAccelerated" />
+        <attr name="uiOptions" />
     </declare-styleable>
     
     <!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 65dce49..73443a0 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -84,6 +84,9 @@
          specified for -large and -xlarge configurations. -->
     <dimen name="config_prefDialogWidth">320dp</dimen>
 
+    <!-- Enables or disables fading edges when marquee is enabled in TextView. -->
+    <bool name="config_ui_enableFadingMarquee">true</bool>
+
     <!-- Whether dialogs should close automatically when the user touches outside
          of them.  This should not normally be modified. -->
     <bool name="config_closeDialogWhenTouchOutside">false</bool>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index b3e50ea..e534e9b 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -50,12 +50,17 @@
     <dimen name="fastscroll_thumb_height">52dp</dimen>
     <!-- Min width for a tablet device -->
     <dimen name="min_xlarge_screen_width">800dp</dimen>
-    <!-- Default height of a key in the password keyboard for alpha -->
+
+    <!-- Default height of a key in the password keyboard for alpha (used by keyguard) -->
     <dimen name="password_keyboard_key_height_alpha">56dip</dimen>
-    <!-- Default height of a key in the password keyboard for numeric -->
+    <!-- Default height of a key in the password keyboard for numeric (used by keyguard) -->
     <dimen name="password_keyboard_key_height_numeric">56dip</dimen>
-    <!-- Default correction for the space key in the password keyboard -->
+    <!-- Default correction for the space key in the password keyboard  (used by keyguard) -->
     <dimen name="password_keyboard_spacebar_vertical_correction">4dip</dimen>
+    <!-- Default horizontal gap between keys in the password keyboard (used by keyguard) -->
+    <dimen name="password_keyboard_horizontalGap">3dip</dimen>
+    <!-- Default vertical gap between keys in the password keyboard (used by keyguard) -->
+    <dimen name="password_keyboard_verticalGap">9dip</dimen>
 
     <!-- Default target placement radius for MultiWaveView -->
     <dimen name="multiwaveview_target_placement_radius">135dip</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 87e9249..1ba54cf 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1783,11 +1783,14 @@
   <public type="attr" name="minResizeHeight" />
 
   <public type="attr" name="actionBarWidgetTheme" />
+  <public type="attr" name="uiOptions" />
+
+  <public type="attr" name="subtypeLocale" />
+  <public type="attr" name="subtypeExtraValue" />
 
   <public type="style" name="TextAppearance.SuggestionHighlight" />
-  <public type="style" name="Theme.Holo.SplitActionBarWhenNarrow" />
-  <public type="style" name="Theme.Holo.Light.SplitActionBarWhenNarrow" />
 
+  <public type="style" name="Theme.Holo.Light.DarkActionBar" />
   <public type="style" name="Widget.Holo.Button.Borderless.Small" />
   <public type="style" name="Widget.Holo.Light.Button.Borderless.Small" />
   <public type="style" name="TextAppearance.Holo.Widget.ActionBar.Title.Inverse" />
@@ -1802,12 +1805,183 @@
   <public type="style" name="Widget.Holo.Light.ActionBar.TabView.Inverse" />
   <public type="style" name="Widget.Holo.Light.ActionBar.TabText.Inverse" />
   <public type="style" name="Widget.Holo.Light.ActionMode.Inverse" />
-  <public type="style" name="Theme.Holo.SolidActionBar" />
-  <public type="style" name="Theme.Holo.Light.SolidActionBar" />
-  <public type="style" name="Theme.Holo.Light.SolidActionBar.Inverse" />
-  <public type="style" name="Theme.Holo.SolidActionBar.SplitActionBarWhenNarrow" />
-  <public type="style" name="Theme.Holo.Light.SolidActionBar.SplitActionBarWhenNarrow" />
-  <public type="style" name="Theme.Holo.Light.SolidActionBar.Inverse.SplitActionBarWhenNarrow" />
+
+  <public type="style" name="Theme.DeviceDefault" />
+  <public type="style" name="Theme.DeviceDefault.NoActionBar" />
+  <public type="style" name="Theme.DeviceDefault.NoActionBar.Fullscreen" />
+  <public type="style" name="Theme.DeviceDefault.Light" />
+  <public type="style" name="Theme.DeviceDefault.Light.NoActionBar" />
+  <public type="style" name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" />
+  <public type="style" name="Theme.DeviceDefault.Dialog" />
+  <public type="style" name="Theme.DeviceDefault.Dialog.MinWidth" />
+  <public type="style" name="Theme.DeviceDefault.Dialog.NoActionBar" />
+  <public type="style" name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" />
+  <public type="style" name="Theme.DeviceDefault.Light.Dialog" />
+  <public type="style" name="Theme.DeviceDefault.Light.Dialog.MinWidth" />
+  <public type="style" name="Theme.DeviceDefault.Light.Dialog.NoActionBar" />
+  <public type="style" name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" />
+  <public type="style" name="Theme.DeviceDefault.DialogWhenLarge" />
+  <public type="style" name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" />
+  <public type="style" name="Theme.DeviceDefault.Light.DialogWhenLarge" />
+  <public type="style" name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" />
+  <public type="style" name="Theme.DeviceDefault.Panel" />
+  <public type="style" name="Theme.DeviceDefault.Light.Panel" />
+  <public type="style" name="Theme.DeviceDefault.Wallpaper" />
+  <public type="style" name="Theme.DeviceDefault.Wallpaper.NoTitleBar" />
+  <public type="style" name="Theme.DeviceDefault.InputMethod" />
+  <public type="style" name="Theme.DeviceDefault.Light.DarkActionBar" />
+
+  <public type="style" name="Widget.DeviceDefault" />
+  <public type="style" name="Widget.DeviceDefault.Button" />
+  <public type="style" name="Widget.DeviceDefault.Button.Small" />
+  <public type="style" name="Widget.DeviceDefault.Button.Inset" />
+  <public type="style" name="Widget.DeviceDefault.Button.Toggle" />
+  <public type="style" name="Widget.DeviceDefault.Button.Borderless.Small" />
+  <public type="style" name="Widget.DeviceDefault.TextView" />
+  <public type="style" name="Widget.DeviceDefault.AutoCompleteTextView" />
+  <public type="style" name="Widget.DeviceDefault.CompoundButton.CheckBox" />
+  <public type="style" name="Widget.DeviceDefault.ListView.DropDown" />
+  <public type="style" name="Widget.DeviceDefault.EditText" />
+  <public type="style" name="Widget.DeviceDefault.ExpandableListView" />
+  <public type="style" name="Widget.DeviceDefault.GridView" />
+  <public type="style" name="Widget.DeviceDefault.ImageButton" />
+  <public type="style" name="Widget.DeviceDefault.ListView" />
+  <public type="style" name="Widget.DeviceDefault.PopupWindow" />
+  <public type="style" name="Widget.DeviceDefault.ProgressBar" />
+  <public type="style" name="Widget.DeviceDefault.ProgressBar.Horizontal" />
+  <public type="style" name="Widget.DeviceDefault.ProgressBar.Small" />
+  <public type="style" name="Widget.DeviceDefault.ProgressBar.Small.Title" />
+  <public type="style" name="Widget.DeviceDefault.ProgressBar.Large" />
+  <public type="style" name="Widget.DeviceDefault.SeekBar" />
+  <public type="style" name="Widget.DeviceDefault.RatingBar" />
+  <public type="style" name="Widget.DeviceDefault.RatingBar.Indicator" />
+  <public type="style" name="Widget.DeviceDefault.RatingBar.Small" />
+  <public type="style" name="Widget.DeviceDefault.CompoundButton.RadioButton" />
+  <public type="style" name="Widget.DeviceDefault.ScrollView" />
+  <public type="style" name="Widget.DeviceDefault.HorizontalScrollView" />
+  <public type="style" name="Widget.DeviceDefault.Spinner" />
+  <public type="style" name="Widget.DeviceDefault.CompoundButton.Star" />
+  <public type="style" name="Widget.DeviceDefault.TabWidget" />
+  <public type="style" name="Widget.DeviceDefault.WebTextView" />
+  <public type="style" name="Widget.DeviceDefault.WebView" />
+  <public type="style" name="Widget.DeviceDefault.DropDownItem" />
+  <public type="style" name="Widget.DeviceDefault.DropDownItem.Spinner" />
+  <public type="style" name="Widget.DeviceDefault.TextView.SpinnerItem" />
+  <public type="style" name="Widget.DeviceDefault.ListPopupWindow" />
+  <public type="style" name="Widget.DeviceDefault.PopupMenu" />
+  <public type="style" name="Widget.DeviceDefault.ActionButton" />
+  <public type="style" name="Widget.DeviceDefault.ActionButton.Overflow" />
+  <public type="style" name="Widget.DeviceDefault.ActionButton.TextButton" />
+  <public type="style" name="Widget.DeviceDefault.ActionMode" />
+  <public type="style" name="Widget.DeviceDefault.ActionButton.CloseMode" />
+  <public type="style" name="Widget.DeviceDefault.ActionBar" />
+  <public type="style" name="Widget.DeviceDefault.Button.Borderless" />
+  <public type="style" name="Widget.DeviceDefault.Tab" />
+  <public type="style" name="Widget.DeviceDefault.CalendarView" />
+  <public type="style" name="Widget.DeviceDefault.DatePicker" />
+  <public type="style" name="Widget.DeviceDefault.ActionBar.TabView" />
+  <public type="style" name="Widget.DeviceDefault.ActionBar.TabText" />
+  <public type="style" name="Widget.DeviceDefault.ActionBar.TabBar" />
+  <public type="style" name="Widget.DeviceDefault.ActionBar.Solid" />
+  <public type="style" name="Widget.DeviceDefault.Light" />
+  <public type="style" name="Widget.DeviceDefault.Light.Button" />
+  <public type="style" name="Widget.DeviceDefault.Light.Button.Small" />
+  <public type="style" name="Widget.DeviceDefault.Light.Button.Inset" />
+  <public type="style" name="Widget.DeviceDefault.Light.Button.Toggle" />
+  <public type="style" name="Widget.DeviceDefault.Light.Button.Borderless.Small" />
+  <public type="style" name="Widget.DeviceDefault.Light.TextView" />
+  <public type="style" name="Widget.DeviceDefault.Light.AutoCompleteTextView" />
+  <public type="style" name="Widget.DeviceDefault.Light.CompoundButton.CheckBox" />
+  <public type="style" name="Widget.DeviceDefault.Light.ListView.DropDown" />
+  <public type="style" name="Widget.DeviceDefault.Light.EditText" />
+  <public type="style" name="Widget.DeviceDefault.Light.ExpandableListView" />
+  <public type="style" name="Widget.DeviceDefault.Light.GridView" />
+  <public type="style" name="Widget.DeviceDefault.Light.ImageButton" />
+  <public type="style" name="Widget.DeviceDefault.Light.ListView" />
+  <public type="style" name="Widget.DeviceDefault.Light.PopupWindow" />
+  <public type="style" name="Widget.DeviceDefault.Light.ProgressBar" />
+  <public type="style" name="Widget.DeviceDefault.Light.ProgressBar.Horizontal" />
+  <public type="style" name="Widget.DeviceDefault.Light.ProgressBar.Small" />
+  <public type="style" name="Widget.DeviceDefault.Light.ProgressBar.Small.Title" />
+  <public type="style" name="Widget.DeviceDefault.Light.ProgressBar.Large" />
+  <public type="style" name="Widget.DeviceDefault.Light.ProgressBar.Inverse" />
+  <public type="style" name="Widget.DeviceDefault.Light.ProgressBar.Small.Inverse" />
+  <public type="style" name="Widget.DeviceDefault.Light.ProgressBar.Large.Inverse" />
+  <public type="style" name="Widget.DeviceDefault.Light.SeekBar" />
+  <public type="style" name="Widget.DeviceDefault.Light.RatingBar" />
+  <public type="style" name="Widget.DeviceDefault.Light.RatingBar.Indicator" />
+  <public type="style" name="Widget.DeviceDefault.Light.RatingBar.Small" />
+  <public type="style" name="Widget.DeviceDefault.Light.CompoundButton.RadioButton" />
+  <public type="style" name="Widget.DeviceDefault.Light.ScrollView" />
+  <public type="style" name="Widget.DeviceDefault.Light.HorizontalScrollView" />
+  <public type="style" name="Widget.DeviceDefault.Light.Spinner" />
+  <public type="style" name="Widget.DeviceDefault.Light.CompoundButton.Star" />
+  <public type="style" name="Widget.DeviceDefault.Light.TabWidget" />
+  <public type="style" name="Widget.DeviceDefault.Light.WebTextView" />
+  <public type="style" name="Widget.DeviceDefault.Light.WebView" />
+  <public type="style" name="Widget.DeviceDefault.Light.DropDownItem" />
+  <public type="style" name="Widget.DeviceDefault.Light.DropDownItem.Spinner" />
+  <public type="style" name="Widget.DeviceDefault.Light.TextView.SpinnerItem" />
+  <public type="style" name="Widget.DeviceDefault.Light.ListPopupWindow" />
+  <public type="style" name="Widget.DeviceDefault.Light.PopupMenu" />
+  <public type="style" name="Widget.DeviceDefault.Light.Tab" />
+  <public type="style" name="Widget.DeviceDefault.Light.CalendarView" />
+  <public type="style" name="Widget.DeviceDefault.Light.ActionButton" />
+  <public type="style" name="Widget.DeviceDefault.Light.ActionButton.Overflow" />
+  <public type="style" name="Widget.DeviceDefault.Light.ActionMode" />
+  <public type="style" name="Widget.DeviceDefault.Light.ActionButton.CloseMode" />
+  <public type="style" name="Widget.DeviceDefault.Light.ActionBar" />
+  <public type="style" name="Widget.DeviceDefault.Light.ActionBar.TabView" />
+  <public type="style" name="Widget.DeviceDefault.Light.ActionBar.TabText" />
+  <public type="style" name="Widget.DeviceDefault.Light.ActionBar.TabBar" />
+  <public type="style" name="Widget.DeviceDefault.Light.ActionBar.Solid" />
+  <public type="style" name="Widget.DeviceDefault.Light.ActionBar.Solid.Inverse" />
+  <public type="style" name="Widget.DeviceDefault.Light.ActionBar.TabBar.Inverse" />
+  <public type="style" name="Widget.DeviceDefault.Light.ActionBar.TabView.Inverse" />
+  <public type="style" name="Widget.DeviceDefault.Light.ActionBar.TabText.Inverse" />
+  <public type="style" name="Widget.DeviceDefault.Light.ActionMode.Inverse" />
+
+  <public type="style" name="TextAppearance.DeviceDefault" />
+  <public type="style" name="TextAppearance.DeviceDefault.Inverse" />
+  <public type="style" name="TextAppearance.DeviceDefault.Large" />
+  <public type="style" name="TextAppearance.DeviceDefault.Large.Inverse" />
+  <public type="style" name="TextAppearance.DeviceDefault.Medium" />
+  <public type="style" name="TextAppearance.DeviceDefault.Medium.Inverse" />
+  <public type="style" name="TextAppearance.DeviceDefault.Small" />
+  <public type="style" name="TextAppearance.DeviceDefault.Small.Inverse" />
+  <public type="style" name="TextAppearance.DeviceDefault.SearchResult.Title" />
+  <public type="style" name="TextAppearance.DeviceDefault.SearchResult.Subtitle" />
+  <public type="style" name="TextAppearance.DeviceDefault.WindowTitle" />
+  <public type="style" name="TextAppearance.DeviceDefault.DialogWindowTitle" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.Button" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.IconMenu.Item" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.TabWidget" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.TextView" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.TextView.PopupMenu" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.DropDownHint" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.DropDownItem" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.TextView.SpinnerItem" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.EditText" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.PopupMenu" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.PopupMenu.Large" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.PopupMenu.Small" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.ActionBar.Title" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.ActionMode.Title" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.ActionBar.Title.Inverse" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle.Inverse" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.ActionMode.Title.Inverse" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle.Inverse" />
+  <public type="style" name="TextAppearance.DeviceDefault.Widget.ActionBar.Menu" />
+
+  <public type="style" name="DeviceDefault.ButtonBar" />
+  <public type="style" name="DeviceDefault.ButtonBar.AlertDialog" />
+  <public type="style" name="DeviceDefault.SegmentedButton" />
+  <public type="style" name="DeviceDefault.Light.ButtonBar" />
+  <public type="style" name="DeviceDefault.Light.ButtonBar.AlertDialog" />
+  <public type="style" name="DeviceDefault.Light.SegmentedButton" />
 
   <public type="integer" name="status_bar_notification_info_maxnum" />
   <public type="string" name="status_bar_notification_info_overflow" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index c5aa4b2..aa4387e5 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -212,8 +212,8 @@
     <!-- android.net.http Error strings --> <skip />
     <!-- Displayed when a web request was successful. -->
     <string name="httpErrorOk">OK</string>
-    <!-- Displayed when a web request failed because we don't know the exact reason. -->
-    <string name="httpError">The Web page contains an error.</string>
+    <!-- Displayed when a web request failed with a generic network error. -->
+    <string name="httpError">A network error occurred.</string>
     <!-- Displayed when a web request failed because the URL could not be found. -->
     <string name="httpErrorLookup">The URL could not be found.</string>
     <!-- Displayed when a web request failed because the site's authentication scheme is not supported by us. -->
@@ -1358,14 +1358,6 @@
       with Near Field Communication (NFC) tags, cards, and readers.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_vpn">intercept and modify all network traffic</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_vpn">Allows an application to intercept and
-      inspect all network traffic to establish a VPN connection.
-      Malicious applications may monitor, redirect, or modify network packets
-      without your knowledge.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_disableKeyguard">disable keylock</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_disableKeyguard">Allows an application to disable
@@ -2159,11 +2151,11 @@
 
     <!-- Title of an application permission, listed so the user can choose whether
         they want to allow the application to do this. [CHAR LIMIT=NONE] -->
-    <string name="permlab_readWriteOwnVoicemail">Access voicemails managed by this application</string>
+    <string name="permlab_addVoicemail">add voicemail</string>
     <!-- Description of an application permission, listed so the user can choose whether
         they want to allow the application to do this. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_readWriteOwnVoicemail">Allows the application to store and retrieve only
-      voicemails that its associated service can access.</string>
+    <string name="permdesc_addVoicemail">Allows the application to add messages
+      to your voicemail inbox.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether
         they want to allow the application to do this. -->
@@ -2591,10 +2583,10 @@
         <item quantity="other">Open Wi-Fi networks available</item>
     </plurals>
 
-     <!-- A notification is shown the first time a wireless network is disabled due to bad connectivity.  This is the notification's title / ticker. -->
-    <string name="wifi_watchdog_network_disabled">A Wi-Fi network was disabled</string>
-    <!--  A notification is shown the first time a wireless network is disabled due to bad connectivity.  This is the notification's message which leads to the settings pane -->
-    <string name="wifi_watchdog_network_disabled_detailed">A Wi-Fi network was temporarily disabled due to bad connectivity.</string>
+     <!-- A notification is shown when a user's selected SSID is later disabled due to connectivity problems.  This is the notification's title / ticker. -->
+     <string name="wifi_watchdog_network_disabled">Couldn\'t connect to Wi-Fi</string>
+     <!-- A notification is shown when a user's selected SSID is later disabled due to connectivity problems.  This is a partial string of the message, which will also include the (possibly truncated) hotspot name. -->
+    <string name="wifi_watchdog_network_disabled_detailed"> has a poor internet connection.</string>
 
     <!-- Do not translate. Default access point SSID used for tethering -->
     <string name="wifi_tether_configure_ssid_default" translatable="false">AndroidAP</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 5aa47b7..0c6e20f 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -14,6 +14,20 @@
      limitations under the License.
 -->
 
+<!--
+===============================================================
+                        PLEASE READ
+===============================================================
+
+The Holo themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+                        PLEASE READ
+===============================================================
+ -->
 <resources>
     <!-- Global Theme Styles -->
     <eat-comment />
@@ -95,19 +109,6 @@
         <item name="windowExitAnimation">@anim/dialog_exit</item>
     </style>
 
-    <!-- Standard animations for hiding and showing the status bar. -->
-    <style name="Animation.StatusBar">
-        <item name="windowEnterAnimation">@anim/status_bar_enter</item>
-        <item name="windowExitAnimation">@anim/status_bar_exit</item>
-    </style>
-
-    <!-- {@hide} -->
-    <style name="Animation.StatusBar.IntruderAlert"
-        parent="@android:style/Animation.StatusBar">
-        <item name="android:windowEnterAnimation">@anim/priority_alert_enter</item>
-        <item name="android:windowExitAnimation">@anim/priority_alert_exit</item>
-    </style>
-
     <!-- Standard animations for a translucent window or activity.  This
          style is <em>not<em> used by default for the translucent theme
          (since translucent activities are a special case that have no
@@ -1743,6 +1744,7 @@
     </style>
 
     <style name="Widget.Holo.Spinner.DropDown.ActionBar">
+        <item name="android:background">@android:drawable/spinner_ab_holo_dark</item>
     </style>
 
     <style name="Widget.Holo.CompoundButton.Star" parent="Widget.CompoundButton.Star">
@@ -2130,6 +2132,7 @@
     </style>
 
     <style name="Widget.Holo.Light.Spinner.DropDown.ActionBar">
+        <item name="android:background">@android:drawable/spinner_ab_holo_light</item>
     </style>
 
     <style name="Widget.Holo.Light.CompoundButton.Star" parent="Widget.CompoundButton.Star">
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
new file mode 100644
index 0000000..7f1891e
--- /dev/null
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -0,0 +1,741 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+
+<!--
+===============================================================
+                        PLEASE READ
+===============================================================
+This file contains the themes that are the Device Defaults.
+If you want to edit styles to skin your device, do it here.
+We recommend that you do not edit styles.xml and instead edit
+this file.
+
+Editing this file instead of styles.xml will greatly simplify
+merges for future platform versions and CTS compliance will be
+easier.
+===============================================================
+                        PLEASE READ
+===============================================================
+ -->
+<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.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.EditText.NumberPickerInputText" parent="Widget.Holo.EditText.NumberPickerInputText">
+
+    </style>
+    <style name="Widget.DeviceDefault.ExpandableListView.White" parent="Widget.Holo.ExpandableListView.White">
+
+    </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.ImageButton.NumberPickerDownButton" parent="Widget.Holo.ImageButton.NumberPickerDownButton">
+
+    </style>
+    <style name="Widget.DeviceDefault.ImageButton.NumberPickerUpButton" parent="Widget.Holo.ImageButton.NumberPickerUpButton">
+
+    </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.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.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.EditText.NumberPickerInputText" parent="Widget.Holo.Light.EditText.NumberPickerInputText">
+
+    </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.ImageButton.NumberPickerDownButton" parent="Widget.Holo.Light.ImageButton.NumberPickerDownButton">
+
+    </style>
+    <style name="Widget.DeviceDefault.Light.ImageButton.NumberPickerUpButton" parent="Widget.Holo.Light.ImageButton.NumberPickerUpButton">
+
+    </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>
+
+
+    <!-- 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>
+
+
+    <!-- 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>
+
+
+    <!-- AlertDialog Styles -->
+    <style name="AlertDialog.DeviceDefault" parent="AlertDialog.Holo">
+
+    </style>
+    <style name="AlertDialog.DeviceDefault.Light" parent="AlertDialog.DeviceDefault.Light" >
+
+    </style>
+
+
+    <!-- Animation Styles -->
+    <style name="Animation.DeviceDefault.Activity" parent="Animation.Holo.Activity">
+
+    </style>
+    <style name="Animation.DeviceDefault.Dialog" parent="Animation.Holo.Dialog">
+
+    </style>
+
+
+    <!-- DialogWindowTitle Styles -->
+    <style name="DialogWindowTitle.DeviceDefault" parent="DialogWindowTitle.Holo">
+
+    </style>
+    <style name="DialogWindowTitle.DeviceDefault.Light" parent="DialogWindowTitle.Holo.Light">
+
+    </style>
+
+
+    <!-- WindowTitle Styles -->
+    <style name="WindowTitle.DeviceDefault" parent="WindowTitle.Holo">
+
+    </style>
+    <style name="WindowTitleBackground.DeviceDefault" parent="WindowTitleBackground.Holo">
+
+    </style>
+
+
+    <!-- Other Styles -->
+    <style name="DeviceDefault.ButtonBar" parent="Holo.ButtonBar" >
+
+    </style>
+    <style name="DeviceDefault.ButtonBar.AlertDialog" parent="Holo.ButtonBar.AlertDialog" >
+
+    </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>
+</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 3e7c5ca..82299b8 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -14,6 +14,20 @@
      limitations under the License.
 -->
 
+<!--
+===============================================================
+                        PLEASE READ
+===============================================================
+
+The Holo themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see themes_device_defaults.xml.
+
+===============================================================
+                        PLEASE READ
+===============================================================
+ -->
 <resources>
     <!-- The default system theme. This is the theme used for activities
          that have not explicitly set their own theme.
@@ -171,6 +185,9 @@
         <item name="panelColorForeground">?android:attr/textColorPrimary</item>
         <item name="panelTextAppearance">?android:attr/textAppearance</item>
 
+        <item name="panelMenuIsCompact">false</item>
+        <item name="panelMenuListWidth">296dip</item>
+
         <!-- Scrollbar attributes -->
         <item name="scrollbarFadeDuration">250</item>
         <item name="scrollbarDefaultDelayBeforeFade">300</item> 
@@ -741,6 +758,22 @@
         <item name="android:background">@null</item>
     </style>
 
+    <style name="Theme.Holo.CompactMenu">
+        <!-- Menu/item attributes -->
+        <item name="android:itemTextAppearance">?android:attr/textAppearanceMedium</item>
+        <item name="android:listViewStyle">@android:style/Widget.Holo.ListView</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.DropDownUp</item>
+        <item name="android:background">@null</item>
+    </style>
+
+    <style name="Theme.Holo.Light.CompactMenu">
+        <!-- Menu/item attributes -->
+        <item name="android:itemTextAppearance">?android:attr/textAppearanceMedium</item>
+        <item name="android:listViewStyle">@android:style/Widget.Holo.Light.ListView</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.DropDownUp</item>
+        <item name="android:background">@null</item>
+    </style>
+
     <!-- @hide -->
     <style name="Theme.Dialog.AppError" parent="Theme.Holo.Dialog">
         <item name="windowFrame">@null</item>
@@ -933,13 +966,17 @@
         <item name="toastFrameBackground">@android:drawable/toast_frame_holo</item>
         
         <!-- Panel attributes -->
-        <item name="panelBackground">@android:drawable/menu_background</item>
+        <item name="panelBackground">@android:drawable/menu_dropdown_panel_holo_dark</item>
         <item name="panelFullBackground">@android:drawable/menu_background_fill_parent_width</item>
         <!-- These three attributes do not seems to be used by the framework. Declared public though -->
         <item name="panelColorBackground">#000</item>
         <item name="panelColorForeground">?android:attr/textColorPrimary</item>
         <item name="panelTextAppearance">?android:attr/textAppearance</item>
 
+        <item name="panelMenuIsCompact">true</item>
+        <item name="panelMenuListWidth">250dip</item>
+        <item name="panelMenuListTheme">@android:style/Theme.Holo.CompactMenu</item>
+
         <!-- Scrollbar attributes -->
         <item name="scrollbarFadeDuration">250</item>
         <item name="scrollbarDefaultDelayBeforeFade">300</item> 
@@ -1207,7 +1244,7 @@
         <item name="windowNoTitle">false</item>
         <item name="windowFullscreen">false</item>
         <item name="windowIsFloating">false</item>
-        <item name="windowContentOverlay">@null</item>
+        <item name="android:windowContentOverlay">@android:drawable/ab_solid_shadow_holo</item>
         <item name="windowShowWallpaper">false</item>
         <item name="windowTitleStyle">@android:style/WindowTitle.Holo</item>
         <item name="windowTitleSize">25dip</item>
@@ -1230,13 +1267,17 @@
         <item name="toastFrameBackground">@android:drawable/toast_frame_holo</item>
         
         <!-- Panel attributes -->
-        <item name="panelBackground">@android:drawable/menu_background</item>
+        <item name="panelBackground">@android:drawable/menu_dropdown_panel_holo_light</item>
         <item name="panelFullBackground">@android:drawable/menu_background_fill_parent_width</item>
         <!-- These three attributes do not seems to be used by the framework. Declared public though -->
         <item name="panelColorBackground">#000</item>
         <item name="panelColorForeground">?android:attr/textColorPrimary</item>
         <item name="panelTextAppearance">?android:attr/textAppearance</item>
 
+        <item name="panelMenuIsCompact">true</item>
+        <item name="panelMenuListWidth">250dip</item>
+        <item name="panelMenuListTheme">@android:style/Theme.Holo.Light.CompactMenu</item>
+
         <!-- Scrollbar attributes -->
         <item name="scrollbarFadeDuration">250</item>
         <item name="scrollbarDefaultDelayBeforeFade">300</item>
@@ -1337,7 +1378,7 @@
         <item name="actionBarTabTextStyle">@style/Widget.Holo.Light.ActionBar.TabText</item>
         <item name="actionModeStyle">@style/Widget.Holo.Light.ActionMode</item>
         <item name="actionModeCloseButtonStyle">@style/Widget.Holo.Light.ActionButton.CloseMode</item>
-        <item name="actionBarStyle">@android:style/Widget.Holo.Light.ActionBar</item>
+        <item name="android:actionBarStyle">@android:style/Widget.Holo.Light.ActionBar.Solid</item>
         <item name="actionBarSize">@dimen/action_bar_default_height</item>
         <item name="actionModePopupWindowStyle">@android:style/Widget.Holo.Light.PopupWindow.ActionMode</item>
         <item name="actionBarWidgetTheme">@null</item>
@@ -1384,22 +1425,10 @@
 
     </style>
 
-    <!-- Variant of the holographic (dark) theme that has a solid (opaque) action bar. -->
-    <style name="Theme.Holo.SolidActionBar">
-        <item name="android:actionBarStyle">@android:style/Widget.Holo.ActionBar.Solid</item>
-        <item name="android:windowContentOverlay">@android:drawable/ab_solid_shadow_holo</item>
-    </style>
-
-    <!-- Variant of the holographic (light) theme that has a solid (opaque) action bar. -->
-    <style name="Theme.Holo.Light.SolidActionBar">
-        <item name="android:actionBarStyle">@android:style/Widget.Holo.Light.ActionBar.Solid</item>
-        <item name="android:windowContentOverlay">@android:drawable/ab_solid_shadow_holo</item>
-    </style>
-
     <!-- Variant of the holographic (light) theme that has a solid (opaque) action bar
          with an inverse color profile. The dark action bar sharply stands out against
          the light content. -->
-    <style name="Theme.Holo.Light.SolidActionBar.Inverse">
+    <style name="Theme.Holo.Light.DarkActionBar">
         <item name="android:windowContentOverlay">@android:drawable/title_bar_shadow</item>
         <item name="android:actionBarStyle">@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse</item>
         <item name="actionBarWidgetTheme">@android:style/Theme.Holo</item>
@@ -1427,30 +1456,6 @@
         <item name="actionModeWebSearchDrawable">@android:drawable/ic_menu_search_holo_dark</item>
     </style>
 
-    <!-- Variant of the holographic (dark) theme that has a solid
-         (opaque) action bar. The action bar will split across both
-         the top and bottom of the screen when the screen is
-         especially constrained for horizontal space. -->
-    <style name="Theme.Holo.SolidActionBar.SplitActionBarWhenNarrow">
-        <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
-    </style>
-
-    <!-- Variant of the holographic (light) theme that has a solid
-         (opaque) action bar. The action bar will split across both
-         the top and bottom of the screen when the screen is
-         especially constrained for horizontal space. -->
-    <style name="Theme.Holo.Light.SolidActionBar.SplitActionBarWhenNarrow">
-        <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
-    </style>
-
-    <!-- Variant of the holographic (light) theme that has a solid (opaque) action bar
-         with an inverse color profile. The dark action bar sharply stands out against
-         the light content. The action bar will split across both the top and bottom of
-         the screen when the screen is especially constrained for horizontal space. -->
-    <style name="Theme.Holo.Light.SolidActionBar.Inverse.SplitActionBarWhenNarrow">
-        <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
-    </style>
-
     <!-- Variant of the holographic (dark) theme with no action bar. -->
     <style name="Theme.Holo.NoActionBar">
         <item name="android:windowActionBar">false</item>
@@ -1654,18 +1659,4 @@
     <style name="Theme.Holo.Wallpaper.NoTitleBar">
         <item name="android:windowNoTitle">true</item>
     </style>
-
-    <!-- Variant of the holographic (dark) theme with an action bar that
-         splits across the top and bottom of the activity when constrained
-         for horizontal space. -->
-    <style name="Theme.Holo.SplitActionBarWhenNarrow">
-        <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
-    </style>
-
-    <!-- Variant of the holographic (light) theme with an action bar that
-         splits across the top and bottom of the activity when constrained
-         for horizontal space. -->
-    <style name="Theme.Holo.Light.SplitActionBarWhenNarrow">
-        <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
-    </style>
 </resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
new file mode 100644
index 0000000..bf6329d
--- /dev/null
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -0,0 +1,423 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+
+<!--
+===============================================================
+                        PLEASE READ
+===============================================================
+This file contains the themes that are the Device Defaults.
+If you want to edit themes to skin your device, do it here.
+We recommend that you do not edit themes.xml and instead edit
+this file.
+
+Editing this file instead of themes.xml will greatly simplify
+merges for future platform versions and CTS compliance will be
+easier.
+===============================================================
+                        PLEASE READ
+===============================================================
+ -->
+<resources>
+    <style name="Theme.DeviceDefault" parent="Theme.Holo" >
+        <!-- Text styles -->
+        <item name="textAppearance">@android:style/TextAppearance.DeviceDefault</item>
+        <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Inverse</item>
+
+        <item name="textAppearanceLarge">@android:style/TextAppearance.DeviceDefault.Large</item>
+        <item name="textAppearanceMedium">@android:style/TextAppearance.DeviceDefault.Medium</item>
+        <item name="textAppearanceSmall">@android:style/TextAppearance.DeviceDefault.Small</item>
+        <item name="textAppearanceLargeInverse">@android:style/TextAppearance.DeviceDefault.Large.Inverse</item>
+        <item name="textAppearanceMediumInverse">@android:style/TextAppearance.DeviceDefault.Medium.Inverse</item>
+        <item name="textAppearanceSmallInverse">@android:style/TextAppearance.DeviceDefault.Small.Inverse</item>
+        <item name="textAppearanceSearchResultTitle">@android:style/TextAppearance.DeviceDefault.SearchResult.Title</item>
+        <item name="textAppearanceSearchResultSubtitle">@android:style/TextAppearance.DeviceDefault.SearchResult.Subtitle</item>
+
+        <item name="textAppearanceButton">@android:style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+        <item name="textAppearanceLargePopupMenu">@android:style/TextAppearance.DeviceDefault.Widget.PopupMenu.Large</item>
+        <item name="textAppearanceSmallPopupMenu">@android:style/TextAppearance.DeviceDefault.Widget.PopupMenu.Small</item>
+
+        <!-- Button styles -->
+        <item name="buttonStyle">@android:style/Widget.DeviceDefault.Button</item>
+
+        <item name="buttonStyleSmall">@android:style/Widget.DeviceDefault.Button.Small</item>
+        <item name="buttonStyleInset">@android:style/Widget.DeviceDefault.Button.Inset</item>
+
+        <item name="buttonStyleToggle">@android:style/Widget.DeviceDefault.Button.Toggle</item>
+        <item name="switchStyle">@android:style/Widget.DeviceDefault.CompoundButton.Switch</item>
+
+        <item name="borderlessButtonStyle">@android:style/Widget.DeviceDefault.Button.Borderless</item>
+
+        <item name="listSeparatorTextViewStyle">@android:style/Widget.DeviceDefault.TextView.ListSeparator</item>
+
+        <!-- Window attributes -->
+        <item name="windowTitleStyle">@android:style/WindowTitle.DeviceDefault</item>
+        <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground.DeviceDefault</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Activity</item>
+
+        <!-- Dialog attributes -->
+        <item name="alertDialogStyle">@android:style/AlertDialog.DeviceDefault</item>
+        <item name="dialogTheme">@android:style/Theme.DeviceDefault.Dialog</item>
+        <item name="alertDialogTheme">@android:style/Theme.DeviceDefault.Dialog.Alert</item>
+
+        <!-- Text selection handle attributes -->
+        <item name="textSelectHandleWindowStyle">@android:style/Widget.DeviceDefault.TextSelectHandle</item>
+        <item name="textSuggestionsWindowStyle">@android:style/Widget.DeviceDefault.TextSuggestionsPopupWindow</item>
+
+        <!-- Widget styles -->
+        <item name="absListViewStyle">@android:style/Widget.DeviceDefault.AbsListView</item>
+        <item name="autoCompleteTextViewStyle">@android:style/Widget.DeviceDefault.AutoCompleteTextView</item>
+        <item name="checkboxStyle">@android:style/Widget.DeviceDefault.CompoundButton.CheckBox</item>
+        <item name="dropDownListViewStyle">@android:style/Widget.DeviceDefault.ListView.DropDown</item>
+        <item name="editTextStyle">@android:style/Widget.DeviceDefault.EditText</item>
+        <item name="expandableListViewStyle">@android:style/Widget.DeviceDefault.ExpandableListView</item>
+        <item name="expandableListViewWhiteStyle">@android:style/Widget.DeviceDefault.ExpandableListView.White</item>
+        <item name="galleryStyle">@android:style/Widget.DeviceDefault.Gallery</item>
+        <item name="gestureOverlayViewStyle">@android:style/Widget.DeviceDefault.GestureOverlayView</item>
+        <item name="gridViewStyle">@android:style/Widget.DeviceDefault.GridView</item>
+        <item name="imageButtonStyle">@android:style/Widget.DeviceDefault.ImageButton</item>
+        <item name="imageWellStyle">@android:style/Widget.DeviceDefault.ImageWell</item>
+        <item name="listViewStyle">@android:style/Widget.DeviceDefault.ListView</item>
+        <item name="listViewWhiteStyle">@android:style/Widget.DeviceDefault.ListView.White</item>
+        <item name="popupWindowStyle">@android:style/Widget.DeviceDefault.PopupWindow</item>
+        <item name="progressBarStyle">@android:style/Widget.DeviceDefault.ProgressBar</item>
+        <item name="progressBarStyleHorizontal">@android:style/Widget.DeviceDefault.ProgressBar.Horizontal</item>
+        <item name="progressBarStyleSmall">@android:style/Widget.DeviceDefault.ProgressBar.Small</item>
+        <item name="progressBarStyleSmallTitle">@android:style/Widget.DeviceDefault.ProgressBar.Small.Title</item>
+        <item name="progressBarStyleLarge">@android:style/Widget.DeviceDefault.ProgressBar.Large</item>
+        <item name="progressBarStyleInverse">@android:style/Widget.DeviceDefault.ProgressBar.Inverse</item>
+        <item name="progressBarStyleSmallInverse">@android:style/Widget.DeviceDefault.ProgressBar.Small.Inverse</item>
+        <item name="progressBarStyleLargeInverse">@android:style/Widget.DeviceDefault.ProgressBar.Large.Inverse</item>
+        <item name="seekBarStyle">@android:style/Widget.DeviceDefault.SeekBar</item>
+        <item name="ratingBarStyle">@android:style/Widget.DeviceDefault.RatingBar</item>
+        <item name="ratingBarStyleIndicator">@android:style/Widget.DeviceDefault.RatingBar.Indicator</item>
+        <item name="ratingBarStyleSmall">@android:style/Widget.DeviceDefault.RatingBar.Small</item>
+        <item name="radioButtonStyle">@android:style/Widget.DeviceDefault.CompoundButton.RadioButton</item>
+        <item name="scrollViewStyle">@android:style/Widget.DeviceDefault.ScrollView</item>
+        <item name="horizontalScrollViewStyle">@android:style/Widget.DeviceDefault.HorizontalScrollView</item>
+        <item name="dropDownSpinnerStyle">@android:style/Widget.DeviceDefault.Spinner.DropDown</item>
+        <item name="starStyle">@android:style/Widget.DeviceDefault.CompoundButton.Star</item>
+        <item name="tabWidgetStyle">@android:style/Widget.DeviceDefault.TabWidget</item>
+        <item name="textViewStyle">@android:style/Widget.DeviceDefault.TextView</item>
+        <item name="webTextViewStyle">@android:style/Widget.DeviceDefault.WebTextView</item>
+        <item name="webViewStyle">@android:style/Widget.DeviceDefault.WebView</item>
+        <item name="dropDownItemStyle">@android:style/Widget.DeviceDefault.DropDownItem</item>
+        <item name="spinnerDropDownItemStyle">@android:style/Widget.DeviceDefault.DropDownItem.Spinner</item>
+        <item name="spinnerItemStyle">@android:style/Widget.DeviceDefault.TextView.SpinnerItem</item>
+        <item name="dropDownHintAppearance">@android:style/TextAppearance.DeviceDefault.Widget.DropDownHint</item>
+        <item name="keyboardViewStyle">@android:style/Widget.DeviceDefault.KeyboardView</item>
+        <item name="quickContactBadgeStyleWindowSmall">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowSmall</item>
+        <item name="quickContactBadgeStyleWindowMedium">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowMedium</item>
+        <item name="quickContactBadgeStyleWindowLarge">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowLarge</item>
+        <item name="quickContactBadgeStyleSmallWindowSmall">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowSmall</item>
+        <item name="quickContactBadgeStyleSmallWindowMedium">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowMedium</item>
+        <item name="quickContactBadgeStyleSmallWindowLarge">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowLarge</item>
+        <item name="listPopupWindowStyle">@android:style/Widget.DeviceDefault.ListPopupWindow</item>
+        <item name="popupMenuStyle">@android:style/Widget.DeviceDefault.PopupMenu</item>
+        <item name="stackViewStyle">@android:style/Widget.DeviceDefault.StackView</item>
+
+        <!-- Preference styles -->
+        <item name="preferenceScreenStyle">@android:style/Preference.DeviceDefault.PreferenceScreen</item>
+        <item name="preferenceCategoryStyle">@android:style/Preference.DeviceDefault.Category</item>
+        <item name="preferenceStyle">@android:style/Preference.DeviceDefault</item>
+        <item name="preferenceInformationStyle">@android:style/Preference.DeviceDefault.Information</item>
+        <item name="checkBoxPreferenceStyle">@android:style/Preference.DeviceDefault.CheckBoxPreference</item>
+        <item name="switchPreferenceStyle">@android:style/Preference.DeviceDefault.SwitchPreference</item>
+        <item name="yesNoPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference.YesNoPreference</item>
+        <item name="dialogPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference</item>
+        <item name="editTextPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference.EditTextPreference</item>
+        <item name="ringtonePreferenceStyle">@android:style/Preference.DeviceDefault.RingtonePreference</item>
+
+        <!-- Action bar styles -->
+        <item name="actionDropDownStyle">@android:style/Widget.DeviceDefault.Spinner.DropDown.ActionBar</item>
+        <item name="actionButtonStyle">@android:style/Widget.DeviceDefault.ActionButton</item>
+        <item name="actionOverflowButtonStyle">@android:style/Widget.DeviceDefault.ActionButton.Overflow</item>
+        <item name="actionBarTabStyle">@style/Widget.DeviceDefault.ActionBar.TabView</item>
+        <item name="actionBarTabBarStyle">@style/Widget.DeviceDefault.ActionBar.TabBar</item>
+        <item name="actionBarTabTextStyle">@style/Widget.DeviceDefault.ActionBar.TabText</item>
+        <item name="actionModeStyle">@style/Widget.DeviceDefault.ActionMode</item>
+        <item name="actionModeCloseButtonStyle">@style/Widget.DeviceDefault.ActionButton.CloseMode</item>
+        <item name="actionBarStyle">@android:style/Widget.DeviceDefault.ActionBar</item>
+        <item name="actionModePopupWindowStyle">@android:style/Widget.DeviceDefault.PopupWindow.ActionMode</item>
+
+        <item name="buttonBarStyle">@android:style/DeviceDefault.ButtonBar</item>
+        <item name="segmentedButtonStyle">@android:style/DeviceDefault.SegmentedButton</item>
+
+        <item name="searchDialogTheme">@style/Theme.DeviceDefault.SearchBar</item>
+
+        <!-- PreferenceFrameLayout attributes -->
+        <item name="preferenceFrameLayoutStyle">@android:style/Widget.DeviceDefault.PreferenceFrameLayout</item>
+
+        <!-- NumberPicker styles-->
+        <item name="numberPickerUpButtonStyle">@style/Widget.DeviceDefault.ImageButton.NumberPickerUpButton</item>
+        <item name="numberPickerDownButtonStyle">@style/Widget.DeviceDefault.ImageButton.NumberPickerDownButton</item>
+        <item name="numberPickerInputTextStyle">@style/Widget.DeviceDefault.EditText.NumberPickerInputText</item>
+        <item name="numberPickerStyle">@style/Widget.DeviceDefault.NumberPicker</item>
+
+        <!-- CalendarView style-->
+        <item name="calendarViewStyle">@style/Widget.DeviceDefault.CalendarView</item>
+
+        <!-- TimePicker style -->
+        <item name="timePickerStyle">@style/Widget.DeviceDefault.TimePicker</item>
+
+        <!-- DatePicker style -->
+        <item name="datePickerStyle">@style/Widget.DeviceDefault.DatePicker</item>
+    </style>
+    <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Holo.NoActionBar" >
+
+    </style>
+    <style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Holo.NoActionBar.Fullscreen" >
+
+    </style>
+    <style name="Theme.DeviceDefault.Light" parent="Theme.Holo.Light" >
+        <!-- Text styles -->
+        <item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Light</item>
+        <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Light.Inverse</item>
+
+        <item name="textAppearanceLarge">@android:style/TextAppearance.DeviceDefault.Light.Large</item>
+        <item name="textAppearanceMedium">@android:style/TextAppearance.DeviceDefault.Light.Medium</item>
+        <item name="textAppearanceSmall">@android:style/TextAppearance.DeviceDefault.Light.Small</item>
+        <item name="textAppearanceLargeInverse">@android:style/TextAppearance.DeviceDefault.Light.Large.Inverse</item>
+        <item name="textAppearanceMediumInverse">@android:style/TextAppearance.DeviceDefault.Light.Medium.Inverse</item>
+        <item name="textAppearanceSmallInverse">@android:style/TextAppearance.DeviceDefault.Light.Small.Inverse</item>
+        <item name="textAppearanceSearchResultTitle">@android:style/TextAppearance.DeviceDefault.Light.SearchResult.Title</item>
+        <item name="textAppearanceSearchResultSubtitle">@android:style/TextAppearance.DeviceDefault.Light.SearchResult.Subtitle</item>
+
+        <item name="textAppearanceButton">@android:style/TextAppearance.DeviceDefault.Light.Widget.Button</item>
+
+        <item name="textAppearanceLargePopupMenu">@android:style/TextAppearance.DeviceDefault.Light.Widget.PopupMenu.Large</item>
+        <item name="textAppearanceSmallPopupMenu">@android:style/TextAppearance.DeviceDefault.Light.Widget.PopupMenu.Small</item>
+
+        <!-- Button styles -->
+        <item name="buttonStyle">@android:style/Widget.DeviceDefault.Light.Button</item>
+
+        <item name="buttonStyleSmall">@android:style/Widget.DeviceDefault.Light.Button.Small</item>
+        <item name="buttonStyleInset">@android:style/Widget.DeviceDefault.Light.Button.Inset</item>
+
+        <item name="buttonStyleToggle">@android:style/Widget.DeviceDefault.Light.Button.Toggle</item>
+
+        <item name="borderlessButtonStyle">@android:style/Widget.DeviceDefault.Light.Button.Borderless</item>
+
+        <item name="listSeparatorTextViewStyle">@android:style/Widget.DeviceDefault.Light.TextView.ListSeparator</item>
+
+        <item name="windowTitleStyle">@android:style/WindowTitle.DeviceDefault</item>
+        <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground.DeviceDefault</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Activity</item>
+
+        <!-- Dialog attributes -->
+        <item name="alertDialogStyle">@android:style/AlertDialog.DeviceDefault.Light</item>
+        <item name="dialogTheme">@android:style/Theme.DeviceDefault.Light.Dialog</item>
+        <item name="alertDialogTheme">@android:style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+        <!-- Text selection handle attributes -->
+        <item name="textSelectHandleWindowStyle">@android:style/Widget.DeviceDefault.TextSelectHandle</item>
+        <item name="textSuggestionsWindowStyle">@android:style/Widget.DeviceDefault.Light.TextSuggestionsPopupWindow</item>
+
+        <!-- Widget styles -->
+        <item name="absListViewStyle">@android:style/Widget.DeviceDefault.Light.AbsListView</item>
+        <item name="autoCompleteTextViewStyle">@android:style/Widget.DeviceDefault.Light.AutoCompleteTextView</item>
+        <item name="checkboxStyle">@android:style/Widget.DeviceDefault.Light.CompoundButton.CheckBox</item>
+        <item name="dropDownListViewStyle">@android:style/Widget.DeviceDefault.ListView.DropDown</item>
+        <item name="editTextStyle">@android:style/Widget.DeviceDefault.Light.EditText</item>
+        <item name="expandableListViewStyle">@android:style/Widget.DeviceDefault.Light.ExpandableListView</item>
+        <item name="expandableListViewWhiteStyle">@android:style/Widget.DeviceDefault.Light.ExpandableListView.White</item>
+        <item name="galleryStyle">@android:style/Widget.DeviceDefault.Light.Gallery</item>
+        <item name="gestureOverlayViewStyle">@android:style/Widget.DeviceDefault.Light.GestureOverlayView</item>
+        <item name="gridViewStyle">@android:style/Widget.DeviceDefault.Light.GridView</item>
+        <item name="imageButtonStyle">@android:style/Widget.DeviceDefault.Light.ImageButton</item>
+        <item name="imageWellStyle">@android:style/Widget.DeviceDefault.Light.ImageWell</item>
+        <item name="listViewStyle">@android:style/Widget.DeviceDefault.Light.ListView</item>
+        <item name="listViewWhiteStyle">@android:style/Widget.DeviceDefault.Light.ListView.White</item>
+        <item name="popupWindowStyle">@android:style/Widget.DeviceDefault.Light.PopupWindow</item>
+        <item name="progressBarStyle">@android:style/Widget.DeviceDefault.Light.ProgressBar</item>
+        <item name="progressBarStyleHorizontal">@android:style/Widget.DeviceDefault.Light.ProgressBar.Horizontal</item>
+        <item name="progressBarStyleSmall">@android:style/Widget.DeviceDefault.Light.ProgressBar.Small</item>
+        <item name="progressBarStyleSmallTitle">@android:style/Widget.DeviceDefault.Light.ProgressBar.Small.Title</item>
+        <item name="progressBarStyleLarge">@android:style/Widget.DeviceDefault.Light.ProgressBar.Large</item>
+        <item name="progressBarStyleInverse">@android:style/Widget.DeviceDefault.Light.ProgressBar.Inverse</item>
+        <item name="progressBarStyleSmallInverse">@android:style/Widget.DeviceDefault.Light.ProgressBar.Small.Inverse</item>
+        <item name="progressBarStyleLargeInverse">@android:style/Widget.DeviceDefault.Light.ProgressBar.Large.Inverse</item>
+        <item name="seekBarStyle">@android:style/Widget.DeviceDefault.Light.SeekBar</item>
+        <item name="ratingBarStyle">@android:style/Widget.DeviceDefault.Light.RatingBar</item>
+        <item name="ratingBarStyleIndicator">@android:style/Widget.DeviceDefault.Light.RatingBar.Indicator</item>
+        <item name="ratingBarStyleSmall">@android:style/Widget.DeviceDefault.Light.RatingBar.Small</item>
+        <item name="radioButtonStyle">@android:style/Widget.DeviceDefault.Light.CompoundButton.RadioButton</item>
+        <item name="scrollViewStyle">@android:style/Widget.DeviceDefault.Light.ScrollView</item>
+        <item name="horizontalScrollViewStyle">@android:style/Widget.DeviceDefault.Light.HorizontalScrollView</item>
+        <item name="dropDownSpinnerStyle">@android:style/Widget.DeviceDefault.Light.Spinner.DropDown</item>
+        <item name="starStyle">@android:style/Widget.DeviceDefault.Light.CompoundButton.Star</item>
+        <item name="tabWidgetStyle">@android:style/Widget.DeviceDefault.Light.TabWidget</item>
+        <item name="textViewStyle">@android:style/Widget.DeviceDefault.Light.TextView</item>
+        <item name="webTextViewStyle">@android:style/Widget.DeviceDefault.Light.WebTextView</item>
+        <item name="webViewStyle">@android:style/Widget.DeviceDefault.Light.WebView</item>
+        <item name="dropDownItemStyle">@android:style/Widget.DeviceDefault.Light.DropDownItem</item>
+        <item name="spinnerDropDownItemStyle">@android:style/Widget.DeviceDefault.Light.DropDownItem.Spinner</item>
+        <item name="spinnerItemStyle">@android:style/Widget.DeviceDefault.TextView.SpinnerItem</item>
+        <item name="dropDownHintAppearance">@android:style/TextAppearance.DeviceDefault.Widget.DropDownHint</item>
+        <item name="keyboardViewStyle">@android:style/Widget.DeviceDefault.KeyboardView</item>
+        <item name="quickContactBadgeStyleWindowSmall">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowSmall</item>
+        <item name="quickContactBadgeStyleWindowMedium">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowMedium</item>
+        <item name="quickContactBadgeStyleWindowLarge">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowLarge</item>
+        <item name="quickContactBadgeStyleSmallWindowSmall">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowSmall</item>
+        <item name="quickContactBadgeStyleSmallWindowMedium">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowMedium</item>
+        <item name="quickContactBadgeStyleSmallWindowLarge">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowLarge</item>
+        <item name="listPopupWindowStyle">@android:style/Widget.DeviceDefault.Light.ListPopupWindow</item>
+        <item name="popupMenuStyle">@android:style/Widget.DeviceDefault.Light.PopupMenu</item>
+        <item name="stackViewStyle">@android:style/Widget.DeviceDefault.StackView</item>
+
+        <!-- Preference styles -->
+        <item name="preferenceScreenStyle">@android:style/Preference.DeviceDefault.PreferenceScreen</item>
+        <item name="preferenceCategoryStyle">@android:style/Preference.DeviceDefault.Category</item>
+        <item name="preferenceStyle">@android:style/Preference.DeviceDefault</item>
+        <item name="preferenceInformationStyle">@android:style/Preference.DeviceDefault.Information</item>
+        <item name="checkBoxPreferenceStyle">@android:style/Preference.DeviceDefault.CheckBoxPreference</item>
+        <item name="switchPreferenceStyle">@android:style/Preference.DeviceDefault.SwitchPreference</item>
+        <item name="yesNoPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference.YesNoPreference</item>
+        <item name="dialogPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference</item>
+        <item name="editTextPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference.EditTextPreference</item>
+        <item name="ringtonePreferenceStyle">@android:style/Preference.DeviceDefault.RingtonePreference</item>
+
+        <!-- Action bar styles -->
+        <item name="actionDropDownStyle">@android:style/Widget.DeviceDefault.Light.Spinner.DropDown.ActionBar</item>
+        <item name="actionButtonStyle">@android:style/Widget.DeviceDefault.Light.ActionButton</item>
+        <item name="actionOverflowButtonStyle">@android:style/Widget.DeviceDefault.Light.ActionButton.Overflow</item>
+        <item name="actionBarTabStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabView</item>
+        <item name="actionBarTabBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabBar</item>
+        <item name="actionBarTabTextStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabText</item>
+        <item name="actionModeStyle">@style/Widget.DeviceDefault.Light.ActionMode</item>
+        <item name="actionModeCloseButtonStyle">@style/Widget.DeviceDefault.Light.ActionButton.CloseMode</item>
+        <item name="actionBarStyle">@android:style/Widget.DeviceDefault.Light.ActionBar</item>
+        <item name="actionModePopupWindowStyle">@android:style/Widget.DeviceDefault.Light.PopupWindow.ActionMode</item>
+
+        <item name="buttonBarStyle">@android:style/DeviceDefault.Light.ButtonBar</item>
+        <item name="segmentedButtonStyle">@android:style/DeviceDefault.Light.SegmentedButton</item>
+
+        <item name="searchDialogTheme">@style/Theme.DeviceDefault.Light.SearchBar</item>
+
+        <!-- NumberPicker attributes and styles-->
+        <item name="numberPickerUpButtonStyle">@style/Widget.DeviceDefault.Light.ImageButton.NumberPickerUpButton</item>
+        <item name="numberPickerDownButtonStyle">@style/Widget.DeviceDefault.Light.ImageButton.NumberPickerDownButton</item>
+        <item name="numberPickerInputTextStyle">@style/Widget.DeviceDefault.Light.EditText.NumberPickerInputText</item>
+        <item name="numberPickerStyle">@style/Widget.DeviceDefault.Light.NumberPicker</item>
+
+        <!-- CalendarView style-->
+        <item name="calendarViewStyle">@style/Widget.DeviceDefault.Light.CalendarView</item>
+
+        <!-- TimePicker style -->
+        <item name="timePickerStyle">@style/Widget.DeviceDefault.Light.TimePicker</item>
+
+        <!-- DatePicker style -->
+        <item name="datePickerStyle">@style/Widget.DeviceDefault.Light.DatePicker</item>
+    </style>
+    <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Holo.Light.NoActionBar" >
+
+    </style>
+    <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Holo.Light.NoActionBar.Fullscreen" >
+
+    </style>
+    <style name="Theme.DeviceDefault.Dialog" parent="Theme.Holo.Dialog" >
+        <item name="android:windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Dialog</item>
+
+        <item name="android:buttonBarStyle">@android:style/DeviceDefault.ButtonBar.AlertDialog</item>
+        <item name="borderlessButtonStyle">@android:style/Widget.DeviceDefault.Button.Borderless.Small</item>
+
+        <item name="textAppearance">@android:style/TextAppearance.DeviceDefault</item>
+        <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Inverse</item>
+    </style>
+    <style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Holo.Dialog.MinWidth" >
+
+    </style>
+    <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Holo.Dialog.NoActionBar" >
+
+    </style>
+    <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Holo.Dialog.NoActionBar.MinWidth" >
+
+    </style>
+    <style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Holo.Light.Dialog" >
+        <item name="android:windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault.Light</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Dialog</item>
+
+        <item name="android:buttonBarStyle">@android:style/DeviceDefault.Light.ButtonBar.AlertDialog</item>
+        <item name="borderlessButtonStyle">@android:style/Widget.DeviceDefault.Light.Button.Borderless.Small</item>
+
+        <item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Light</item>
+        <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Light.Inverse</item>
+    </style>
+    <style name="Theme.DeviceDefault.Light.Dialog.MinWidth" parent="Theme.Holo.Light.Dialog.MinWidth" >
+
+    </style>
+    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar" parent="Theme.Holo.Light.Dialog.NoActionBar" >
+
+    </style>
+    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Holo.Light.Dialog.NoActionBar.MinWidth" >
+
+    </style>
+    <style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Holo.DialogWhenLarge" >
+
+    </style>
+    <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Holo.DialogWhenLarge.NoActionBar" >
+
+    </style>
+    <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Holo.Light.DialogWhenLarge" >
+
+    </style>
+    <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Holo.Light.DialogWhenLarge.NoActionBar" >
+
+    </style>
+    <style name="Theme.DeviceDefault.Panel" parent="Theme.Holo.Panel" >
+
+    </style>
+    <style name="Theme.DeviceDefault.Light.Panel" parent="Theme.Holo.Light.Panel" >
+
+    </style>
+    <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Holo.Wallpaper" >
+
+    </style>
+    <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar" parent="Theme.Holo.Wallpaper.NoTitleBar" >
+
+    </style>
+    <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Holo.InputMethod" >
+
+    </style>
+    <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Holo.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>
+        <item name="actionButtonStyle">@android:style/Widget.DeviceDefault.ActionButton</item>
+        <item name="actionOverflowButtonStyle">@android:style/Widget.DeviceDefault.ActionButton.Overflow</item>
+        <item name="actionBarTabStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabView.Inverse</item>
+        <item name="actionBarTabBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabBar.Inverse</item>
+        <item name="actionBarTabTextStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabText.Inverse</item>
+        <item name="actionModeStyle">@style/Widget.DeviceDefault.Light.ActionMode.Inverse</item>
+        <item name="actionModeCloseButtonStyle">@style/Widget.DeviceDefault.ActionButton.CloseMode</item>
+        <item name="actionModePopupWindowStyle">@android:style/Widget.DeviceDefault.PopupWindow.ActionMode</item>
+
+    </style>
+
+    <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Holo.Dialog.Alert">
+        <item name="windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault</item>
+    </style>
+    <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.DeviceDefault.Light.Dialog.Alert">
+        <item name="windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault.Light</item>
+    </style>
+    <style name="Theme.DeviceDefault.SearchBar" parent="Theme.DeviceDefault.SearchBar">
+
+    </style>
+    <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.DeviceDefault.Light.SearchBar">
+
+    </style>
+</resources>
diff --git a/core/res/res/xml-land/password_kbd_qwerty.xml b/core/res/res/xml-land/password_kbd_qwerty.xml
index fd8bd49..988f9ff 100755
--- a/core/res/res/xml-land/password_kbd_qwerty.xml
+++ b/core/res/res/xml-land/password_kbd_qwerty.xml
@@ -20,8 +20,8 @@
 
 <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:horizontalGap="@dimen/password_keyboard_horizontalGap"
+    android:verticalGap="@dimen/password_keyboard_verticalGap"
     android:keyHeight="@dimen/password_keyboard_key_height_alpha"
     >
 
diff --git a/core/res/res/xml-land/password_kbd_qwerty_shifted.xml b/core/res/res/xml-land/password_kbd_qwerty_shifted.xml
index 9ff6fd7..4941946d 100755
--- a/core/res/res/xml-land/password_kbd_qwerty_shifted.xml
+++ b/core/res/res/xml-land/password_kbd_qwerty_shifted.xml
@@ -20,8 +20,8 @@
 
 <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:horizontalGap="@dimen/password_keyboard_horizontalGap"
+    android:verticalGap="@dimen/password_keyboard_verticalGap"
     android:keyHeight="@dimen/password_keyboard_key_height_alpha"
     >
 
diff --git a/core/res/res/xml-mdpi/password_kbd_qwerty.xml b/core/res/res/xml-mdpi/password_kbd_qwerty.xml
index 82a7c75..265d7dc 100755
--- a/core/res/res/xml-mdpi/password_kbd_qwerty.xml
+++ b/core/res/res/xml-mdpi/password_kbd_qwerty.xml
@@ -20,8 +20,8 @@
 
 <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:horizontalGap="@dimen/password_keyboard_horizontalGap"
+    android:verticalGap="@dimen/password_keyboard_verticalGap"
     android:keyHeight="@dimen/password_keyboard_key_height_alpha"
     >
 
diff --git a/core/res/res/xml-mdpi/password_kbd_qwerty_shifted.xml b/core/res/res/xml-mdpi/password_kbd_qwerty_shifted.xml
index 9fff3cc..7379f69 100755
--- a/core/res/res/xml-mdpi/password_kbd_qwerty_shifted.xml
+++ b/core/res/res/xml-mdpi/password_kbd_qwerty_shifted.xml
@@ -20,8 +20,8 @@
 
 <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:horizontalGap="@dimen/password_keyboard_horizontalGap"
+    android:verticalGap="@dimen/password_keyboard_verticalGap"
     android:keyHeight="@dimen/password_keyboard_key_height_alpha"
     >
 
diff --git a/core/res/res/xml-xlarge/password_kbd_numeric.xml b/core/res/res/xml-xlarge/password_kbd_numeric.xml
index 0253122..3745672 100755
--- a/core/res/res/xml-xlarge/password_kbd_numeric.xml
+++ b/core/res/res/xml-xlarge/password_kbd_numeric.xml
@@ -19,7 +19,8 @@
 -->
 <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="33.33%p"
-    android:verticalGap="0px"
+    android:horizontalGap="@dimen/password_keyboard_horizontalGap"
+    android:verticalGap="@dimen/password_keyboard_verticalGap"
     android:keyHeight="@dimen/password_keyboard_key_height_numeric"
     >
 
diff --git a/core/res/res/xml-xlarge/password_kbd_qwerty.xml b/core/res/res/xml-xlarge/password_kbd_qwerty.xml
index 1009c9a..76b6019 100755
--- a/core/res/res/xml-xlarge/password_kbd_qwerty.xml
+++ b/core/res/res/xml-xlarge/password_kbd_qwerty.xml
@@ -22,8 +22,8 @@
     android:keyWidth="8.272%p"
     keyboardHeight="@dimen/password_keyboard_height"
     android:keyHeight="@dimen/password_keyboard_key_height_alpha"
-    android:horizontalGap="0px"
-    android:verticalGap="0px">
+    android:horizontalGap="@dimen/password_keyboard_horizontalGap"
+    android:verticalGap="@dimen/password_keyboard_verticalGap">
 
     <Row android:keyWidth="8.272%p">
         <Key android:keyLabel="Tab"
diff --git a/core/res/res/xml-xlarge/password_kbd_qwerty_shifted.xml b/core/res/res/xml-xlarge/password_kbd_qwerty_shifted.xml
index cbf17c3..35c3142 100755
--- a/core/res/res/xml-xlarge/password_kbd_qwerty_shifted.xml
+++ b/core/res/res/xml-xlarge/password_kbd_qwerty_shifted.xml
@@ -22,8 +22,8 @@
     android:keyWidth="8.272%p"
     keyboardHeight="@dimen/password_keyboard_height"
     android:keyHeight="@dimen/password_keyboard_key_height_alpha"
-    android:horizontalGap="0px"
-    android:verticalGap="0px">
+    android:horizontalGap="@dimen/password_keyboard_horizontalGap"
+    android:verticalGap="@dimen/password_keyboard_verticalGap">
 
     <Row android:keyWidth="8.272%p">
         <Key android:keyLabel="Tab"
diff --git a/core/res/res/xml-xlarge/password_kbd_symbols.xml b/core/res/res/xml-xlarge/password_kbd_symbols.xml
index a58a023..106dd6e 100755
--- a/core/res/res/xml-xlarge/password_kbd_symbols.xml
+++ b/core/res/res/xml-xlarge/password_kbd_symbols.xml
@@ -22,8 +22,8 @@
     android:keyWidth="8.272%p"
     keyboardHeight="@dimen/password_keyboard_height"
     android:keyHeight="@dimen/password_keyboard_key_height_alpha"
-    android:horizontalGap="0px"
-    android:verticalGap="0px">
+    android:horizontalGap="@dimen/password_keyboard_horizontalGap"
+    android:verticalGap="@dimen/password_keyboard_verticalGap">
 
     <Row android:keyWidth="8.272%p">
         <Key android:keyLabel="Tab"
diff --git a/core/res/res/xml-xlarge/password_kbd_symbols_shift.xml b/core/res/res/xml-xlarge/password_kbd_symbols_shift.xml
index 9d9acf5..1233f78 100755
--- a/core/res/res/xml-xlarge/password_kbd_symbols_shift.xml
+++ b/core/res/res/xml-xlarge/password_kbd_symbols_shift.xml
@@ -20,8 +20,8 @@
 
 <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:horizontalGap="@dimen/password_keyboard_horizontalGap"
+    android:verticalGap="@dimen/password_keyboard_verticalGap"
     android:keyHeight="@dimen/password_keyboard_key_height_alpha">
 
     <Row android:keyWidth="8.272%p"
diff --git a/core/res/res/xml/password_kbd_extension.xml b/core/res/res/xml/password_kbd_extension.xml
index f3fa57b..e8d61fe 100755
--- a/core/res/res/xml/password_kbd_extension.xml
+++ b/core/res/res/xml/password_kbd_extension.xml
@@ -20,8 +20,8 @@
 
 <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:horizontalGap="@dimen/password_keyboard_horizontalGap"
+    android:verticalGap="@dimen/password_keyboard_verticalGap"
     android:keyHeight="@dimen/password_keyboard_key_height_alpha"
     >
 
diff --git a/core/res/res/xml/password_kbd_numeric.xml b/core/res/res/xml/password_kbd_numeric.xml
index 2270b8a..2fd5aa0 100755
--- a/core/res/res/xml/password_kbd_numeric.xml
+++ b/core/res/res/xml/password_kbd_numeric.xml
@@ -19,7 +19,8 @@
 -->
 <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="33.33%p"
-    android:verticalGap="0px"
+    android:horizontalGap="@dimen/password_keyboard_horizontalGap"
+    android:verticalGap="@dimen/password_keyboard_verticalGap"
     android:keyHeight="@dimen/password_keyboard_key_height_numeric"
     >
 
diff --git a/core/res/res/xml/password_kbd_popup_template.xml b/core/res/res/xml/password_kbd_popup_template.xml
index 9b853e2..9fcac2c 100644
--- a/core/res/res/xml/password_kbd_popup_template.xml
+++ b/core/res/res/xml/password_kbd_popup_template.xml
@@ -20,8 +20,8 @@
 
 <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:horizontalGap="@dimen/password_keyboard_horizontalGap"
+    android:verticalGap="@dimen/password_keyboard_verticalGap"
     android:keyHeight="@dimen/password_keyboard_key_height_alpha"
     >
 </Keyboard>
diff --git a/core/res/res/xml/password_kbd_qwerty.xml b/core/res/res/xml/password_kbd_qwerty.xml
index 0a35040..dfe581e 100755
--- a/core/res/res/xml/password_kbd_qwerty.xml
+++ b/core/res/res/xml/password_kbd_qwerty.xml
@@ -20,8 +20,8 @@
 
 <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:horizontalGap="@dimen/password_keyboard_horizontalGap"
+    android:verticalGap="@dimen/password_keyboard_verticalGap"
     android:keyHeight="@dimen/password_keyboard_key_height_alpha"
     >
 
diff --git a/core/res/res/xml/password_kbd_qwerty_shifted.xml b/core/res/res/xml/password_kbd_qwerty_shifted.xml
index 9e9db81..1366c58 100755
--- a/core/res/res/xml/password_kbd_qwerty_shifted.xml
+++ b/core/res/res/xml/password_kbd_qwerty_shifted.xml
@@ -20,8 +20,8 @@
 
 <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:horizontalGap="@dimen/password_keyboard_horizontalGap"
+    android:verticalGap="@dimen/password_keyboard_verticalGap"
     android:keyHeight="@dimen/password_keyboard_key_height_alpha"
     >
 
diff --git a/core/res/res/xml/password_kbd_symbols.xml b/core/res/res/xml/password_kbd_symbols.xml
index 9a94930..5876b0d 100755
--- a/core/res/res/xml/password_kbd_symbols.xml
+++ b/core/res/res/xml/password_kbd_symbols.xml
@@ -20,8 +20,8 @@
 
 <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:horizontalGap="@dimen/password_keyboard_horizontalGap"
+    android:verticalGap="@dimen/password_keyboard_verticalGap"
     android:keyHeight="@dimen/password_keyboard_key_height_alpha"
     >
 
diff --git a/core/res/res/xml/password_kbd_symbols_shift.xml b/core/res/res/xml/password_kbd_symbols_shift.xml
index a972eb2..ee83544 100755
--- a/core/res/res/xml/password_kbd_symbols_shift.xml
+++ b/core/res/res/xml/password_kbd_symbols_shift.xml
@@ -20,8 +20,8 @@
 
 <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:horizontalGap="@dimen/password_keyboard_horizontalGap"
+    android:verticalGap="@dimen/password_keyboard_verticalGap"
     android:keyHeight="@dimen/password_keyboard_key_height_alpha"
     >
 
diff --git a/core/tests/bandwidthtests/Android.mk b/core/tests/bandwidthtests/Android.mk
new file mode 100644
index 0000000..3d56141
--- /dev/null
+++ b/core/tests/bandwidthtests/Android.mk
@@ -0,0 +1,30 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Include all test java files.
+LOCAL_SRC_FILES := \
+	$(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_PACKAGE_NAME := BandwidthTests
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/tests/bandwidthtests/AndroidManifest.xml b/core/tests/bandwidthtests/AndroidManifest.xml
new file mode 100644
index 0000000..24221bc
--- /dev/null
+++ b/core/tests/bandwidthtests/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.bandwidth.tests" >
+
+    <application >
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:name="com.android.bandwidthtest.BandwidthTestRunner"
+        android:targetPackage="com.android.bandwidth.tests"
+        android:label="Bandwidth Tests" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.DEVICE_POWER" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+</manifest>
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
new file mode 100644
index 0000000..73c92b0
--- /dev/null
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
@@ -0,0 +1,217 @@
+/*
+ * 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.bandwidthtest;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo.State;
+import android.net.NetworkStats;
+import android.net.TrafficStats;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Process;
+import android.os.SystemClock;
+import android.telephony.TelephonyManager;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import com.android.bandwidthtest.util.BandwidthTestUtil;
+import com.android.bandwidthtest.util.ConnectionUtil;
+
+import java.io.File;
+
+/**
+ * Test that downloads files from a test server and reports the bandwidth metrics collected.
+ */
+public class BandwidthTest extends InstrumentationTestCase {
+
+    private static final String LOG_TAG = "BandwidthTest";
+    private final static String PROF_LABEL = "PROF_";
+    private final static String PROC_LABEL = "PROC_";
+    private final static int INSTRUMENTATION_IN_PROGRESS = 2;
+
+    private final static String BASE_DIR =
+            Environment.getExternalStorageDirectory().getAbsolutePath();
+    private final static String TMP_FILENAME = "tmp.dat";
+    // Download 10.486 * 106 bytes (+ headers) from app engine test server.
+    private final int FILE_SIZE = 10485613;
+    private Context mContext;
+    private ConnectionUtil mConnectionUtil;
+    private TelephonyManager mTManager;
+    private int mUid;
+    private String mSsid;
+    private String mTestServer;
+    private String mDeviceId;
+    private BandwidthTestRunner mRunner;
+
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mRunner = (BandwidthTestRunner) getInstrumentation();
+        mSsid = mRunner.mSsid;
+        mTestServer = mRunner.mTestServer;
+        mContext = mRunner.getTargetContext();
+        mConnectionUtil = new ConnectionUtil(mContext);
+        mConnectionUtil.initialize();
+        Log.v(LOG_TAG, "Initialized mConnectionUtil");
+        mUid = Process.myUid();
+        mTManager = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        mDeviceId = mTManager.getDeviceId();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mConnectionUtil.cleanUp();
+        super.tearDown();
+    }
+
+    /**
+     * Ensure that downloading on wifi reports reasonable stats.
+     */
+    @LargeTest
+    public void testWifiDownload() {
+        assertTrue(setDeviceWifiAndAirplaneMode(mSsid));
+        NetworkStats pre_test_stats = fetchDataFromProc(mUid);
+        String ts = Long.toString(System.currentTimeMillis());
+
+        String targetUrl = BandwidthTestUtil.buildDownloadUrl(
+                mTestServer, FILE_SIZE, mDeviceId, ts);
+        TrafficStats.startDataProfiling(mContext);
+        File tmpSaveFile = new File(BASE_DIR + File.separator + TMP_FILENAME);
+        assertTrue(BandwidthTestUtil.DownloadFromUrl(targetUrl, tmpSaveFile));
+        NetworkStats prof_stats = TrafficStats.stopDataProfiling(mContext);
+
+        NetworkStats post_test_stats = fetchDataFromProc(mUid);
+        NetworkStats proc_stats = post_test_stats.subtract(pre_test_stats);
+
+        // Output measurements to instrumentation out, so that it can be compared to that of
+        // the server.
+        Bundle results = new Bundle();
+        results.putString("device_id", mDeviceId);
+        results.putString("timestamp", ts);
+        results.putInt("size", FILE_SIZE);
+        AddStatsToResults(PROF_LABEL, prof_stats, results);
+        AddStatsToResults(PROC_LABEL, proc_stats, results);
+        getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);
+
+        // Clean up.
+        assertTrue(cleanUpFile(tmpSaveFile));
+    }
+
+    /**
+     * We want to make sure that if we use the Download Manager to download stuff,
+     * accounting still goes to the app making the call and that the numbers still make sense.
+     */
+    @LargeTest
+    public void testWifiDownloadWithDownloadManager() {
+        assertTrue(setDeviceWifiAndAirplaneMode(mSsid));
+        // If we are using the download manager, then the data that is written to /proc/uid_stat/
+        // is accounted against download manager's uid, since it uses pre-ICS API.
+        int downloadManagerUid = mConnectionUtil.downloadManagerUid();
+        assertTrue(downloadManagerUid >= 0);
+        NetworkStats pre_test_stats = fetchDataFromProc(downloadManagerUid);
+        // start profiling
+        TrafficStats.startDataProfiling(mContext);
+        String ts = Long.toString(System.currentTimeMillis());
+        String targetUrl = BandwidthTestUtil.buildDownloadUrl(
+                mTestServer, FILE_SIZE, mDeviceId, ts);
+        Log.v(LOG_TAG, "Download url: " + targetUrl);
+        File tmpSaveFile = new File(BASE_DIR + File.separator + TMP_FILENAME);
+        assertTrue(mConnectionUtil.startDownloadAndWait(targetUrl, 500000));
+        NetworkStats prof_stats = TrafficStats.stopDataProfiling(mContext);
+        NetworkStats post_test_stats = fetchDataFromProc(downloadManagerUid);
+        NetworkStats proc_stats = post_test_stats.subtract(pre_test_stats);
+
+        // Output measurements to instrumentation out, so that it can be compared to that of
+        // the server.
+        Bundle results = new Bundle();
+        results.putString("device_id", mDeviceId);
+        results.putString("timestamp", ts);
+        results.putInt("size", FILE_SIZE);
+        AddStatsToResults(PROF_LABEL, prof_stats, results);
+        AddStatsToResults(PROC_LABEL, proc_stats, results);
+        getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);
+
+        // Clean up.
+        assertTrue(cleanUpFile(tmpSaveFile));
+    }
+
+    /**
+     * Fetch network data from /proc/uid_stat/uid
+     * @return populated {@link NetworkStats}
+     */
+    public NetworkStats fetchDataFromProc(int uid) {
+        String root_filepath = "/proc/uid_stat/" + uid + "/";
+        File rcv_stat = new File (root_filepath + "tcp_rcv");
+        int rx = BandwidthTestUtil.parseIntValueFromFile(rcv_stat);
+        File snd_stat = new File (root_filepath + "tcp_snd");
+        int tx = BandwidthTestUtil.parseIntValueFromFile(snd_stat);
+        NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
+        stats.addValues(NetworkStats.IFACE_ALL, uid, NetworkStats.TAG_NONE, rx, 0, tx, 0);
+        return stats;
+    }
+
+    /**
+     * Turn on Airplane mode and connect to the wifi
+     * @param ssid of the wifi to connect to
+     * @return true if we successfully connected to a given network.
+     */
+    public boolean setDeviceWifiAndAirplaneMode(String ssid) {
+        mConnectionUtil.setAirplaneMode(mContext, true);
+        assertTrue(mConnectionUtil.connectToWifi(ssid));
+        assertTrue(mConnectionUtil.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
+                ConnectionUtil.LONG_TIMEOUT));
+        return mConnectionUtil.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+                ConnectionUtil.LONG_TIMEOUT);
+    }
+
+    /**
+     * Output the {@link NetworkStats} to Instrumentation out.
+     * @param label to attach to this given stats.
+     * @param stats {@link NetworkStats} to add.
+     * @param results {@link Bundle} to be added to.
+     */
+    public void AddStatsToResults(String label, NetworkStats stats, Bundle results){
+        if (results == null || results.isEmpty()) {
+            Log.e(LOG_TAG, "Empty bundle provided.");
+            return;
+        }
+        for (int i = 0; i < stats.size(); ++i) {
+            android.net.NetworkStats.Entry entry = stats.getValues(i, null);
+            results.putInt(label + "uid", entry.uid);
+            results.putString(label + "iface", entry.iface);
+            results.putInt(label + "tag", entry.tag);
+            results.putLong(label + "tx", entry.txBytes);
+            results.putLong(label + "rx", entry.rxBytes);
+        }
+    }
+
+    /**
+     * Remove file if it exists.
+     * @param file {@link File} to delete.
+     * @return true if successfully deleted the file.
+     */
+    private boolean cleanUpFile(File file) {
+        if (file.exists()) {
+            return file.delete();
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTestRunner.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTestRunner.java
new file mode 100644
index 0000000..290ccee
--- /dev/null
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTestRunner.java
@@ -0,0 +1,38 @@
+/*
+ * 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.bandwidthtest;
+
+import android.os.Bundle;
+import android.test.InstrumentationTestRunner;
+
+public class BandwidthTestRunner extends InstrumentationTestRunner {
+    public String mSsid = "wifi-ssid";
+    public String mTestServer = "http://www.sometestserver.com";
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        String ssidStr= (String) icicle.get("ssid");
+        if (ssidStr != null) {
+            mSsid = ssidStr;
+        }
+        String serverStr = (String) icicle.get("server");
+        if (serverStr != null) {
+            mTestServer = serverStr;
+        }
+    }
+}
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/NetworkState.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/NetworkState.java
new file mode 100644
index 0000000..fae0e76
--- /dev/null
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/NetworkState.java
@@ -0,0 +1,257 @@
+/*
+ * 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.bandwidthtest;
+
+import android.net.NetworkInfo.State;
+import android.util.Log;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Data structure to keep track of the network state transitions.
+ */
+public class NetworkState {
+    /**
+     * Desired direction of state transition.
+     */
+    public enum StateTransitionDirection {
+        TO_DISCONNECTION, TO_CONNECTION, DO_NOTHING
+    }
+    private final String LOG_TAG = "NetworkState";
+    private List<State> mStateDepository;
+    private State mTransitionTarget;
+    private StateTransitionDirection mTransitionDirection;
+    private String mReason = null;         // record mReason of state transition failure
+
+    public NetworkState() {
+        mStateDepository = new ArrayList<State>();
+        mTransitionDirection = StateTransitionDirection.DO_NOTHING;
+        mTransitionTarget = State.UNKNOWN;
+    }
+
+    public NetworkState(State currentState) {
+        mStateDepository = new ArrayList<State>();
+        mStateDepository.add(currentState);
+        mTransitionDirection = StateTransitionDirection.DO_NOTHING;
+        mTransitionTarget = State.UNKNOWN;
+    }
+
+    /**
+     * Reinitialize the network state
+     */
+    public void resetNetworkState() {
+        mStateDepository.clear();
+        mTransitionDirection = StateTransitionDirection.DO_NOTHING;
+        mTransitionTarget = State.UNKNOWN;
+    }
+
+    /**
+     * Set the transition criteria
+     * @param initState initial {@link State}
+     * @param transitionDir explicit {@link StateTransitionDirection}
+     * @param targetState desired {@link State}
+     */
+    public void setStateTransitionCriteria(State initState, StateTransitionDirection transitionDir,
+            State targetState) {
+        if (!mStateDepository.isEmpty()) {
+            mStateDepository.clear();
+        }
+        mStateDepository.add(initState);
+        mTransitionDirection = transitionDir;
+        mTransitionTarget = targetState;
+        Log.v(LOG_TAG, "setStateTransitionCriteria: " + printStates());
+    }
+
+    /**
+     * Record the current state of the network
+     * @param currentState  the current {@link State}
+     */
+    public void recordState(State currentState) {
+        mStateDepository.add(currentState);
+    }
+
+    /**
+     * Verify the state transition
+     * @return true if the requested transition completed successfully.
+     */
+    public boolean validateStateTransition() {
+        Log.v(LOG_TAG, String.format("Print state depository: %s", printStates()));
+        switch (mTransitionDirection) {
+            case DO_NOTHING:
+                Log.v(LOG_TAG, "No direction requested, verifying network states");
+                return validateNetworkStates();
+            case TO_CONNECTION:
+                Log.v(LOG_TAG, "Transition to CONNECTED");
+                return validateNetworkConnection();
+            case TO_DISCONNECTION:
+                Log.v(LOG_TAG, "Transition to DISCONNECTED");
+                return validateNetworkDisconnection();
+            default:
+                Log.e(LOG_TAG, "Invalid transition direction.");
+                return false;
+        }
+    }
+
+    /**
+     * Verify that network states are valid
+     * @return false if any of the states are invalid
+     */
+    private boolean validateNetworkStates() {
+        if (mStateDepository.isEmpty()) {
+            Log.v(LOG_TAG, "no state is recorded");
+            mReason = "no state is recorded.";
+            return false;
+        } else if (mStateDepository.size() > 1) {
+            Log.v(LOG_TAG, "no broadcast is expected, instead broadcast is probably received");
+            mReason = "no broadcast is expected, instead broadcast is probably received";
+            return false;
+        } else if (mStateDepository.get(0) != mTransitionTarget) {
+            Log.v(LOG_TAG, String.format("%s is expected, but it is %s",
+                    mTransitionTarget.toString(),
+                    mStateDepository.get(0).toString()));
+            mReason = String.format("%s is expected, but it is %s",
+                    mTransitionTarget.toString(),
+                    mStateDepository.get(0).toString());
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Verify the network state to disconnection
+     * @return false if any of the state transitions were not valid
+     */
+    private boolean validateNetworkDisconnection() {
+        // Transition from CONNECTED -> DISCONNECTED: CONNECTED->DISCONNECTING->DISCONNECTED
+        StringBuffer str = new StringBuffer ("States: ");
+        str.append(printStates());
+        if (mStateDepository.get(0) != State.CONNECTED) {
+            str.append(String.format(" Initial state should be CONNECTED, but it is %s.",
+                    mStateDepository.get(0)));
+            mReason = str.toString();
+            return false;
+        }
+        State lastState = mStateDepository.get(mStateDepository.size() - 1);
+        if ( lastState != mTransitionTarget) {
+            str.append(String.format(" Last state should be DISCONNECTED, but it is %s",
+                    lastState));
+            mReason = str.toString();
+            return false;
+        }
+        for (int i = 1; i < mStateDepository.size() - 1; i++) {
+            State preState = mStateDepository.get(i-1);
+            State curState = mStateDepository.get(i);
+            if ((preState == State.CONNECTED) && ((curState == State.DISCONNECTING) ||
+                    (curState == State.DISCONNECTED))) {
+                continue;
+            } else if ((preState == State.DISCONNECTING) && (curState == State.DISCONNECTED)) {
+                continue;
+            } else if ((preState == State.DISCONNECTED) && (curState == State.DISCONNECTED)) {
+                continue;
+            } else {
+                str.append(String.format(" Transition state from %s to %s is not valid",
+                        preState.toString(), curState.toString()));
+                mReason = str.toString();
+                return false;
+            }
+        }
+        mReason = str.toString();
+        return true;
+    }
+
+    /**
+     * Verify the network state to connection
+     * @return false if any of the state transitions were not valid
+     */
+    private boolean validateNetworkConnection() {
+        StringBuffer str = new StringBuffer("States ");
+        str.append(printStates());
+        if (mStateDepository.get(0) != State.DISCONNECTED) {
+            str.append(String.format(" Initial state should be DISCONNECTED, but it is %s.",
+                    mStateDepository.get(0)));
+            mReason = str.toString();
+            return false;
+        }
+        State lastState = mStateDepository.get(mStateDepository.size() - 1);
+        if ( lastState != mTransitionTarget) {
+            str.append(String.format(" Last state should be %s, but it is %s", mTransitionTarget,
+                    lastState));
+            mReason = str.toString();
+            return false;
+        }
+        for (int i = 1; i < mStateDepository.size(); i++) {
+            State preState = mStateDepository.get(i-1);
+            State curState = mStateDepository.get(i);
+            if ((preState == State.DISCONNECTED) && ((curState == State.CONNECTING) ||
+                    (curState == State.CONNECTED) || (curState == State.DISCONNECTED))) {
+                continue;
+            } else if ((preState == State.CONNECTING) && (curState == State.CONNECTED)) {
+                continue;
+            } else if ((preState == State.CONNECTED) && (curState == State.CONNECTED)) {
+                continue;
+            } else {
+                str.append(String.format(" Transition state from %s to %s is not valid.",
+                        preState.toString(), curState.toString()));
+                mReason = str.toString();
+                return false;
+            }
+        }
+        mReason = str.toString();
+        return true;
+    }
+
+    /**
+     * Fetch the different network state transitions
+     * @return {@link List} of {@link State}
+     */
+    public List<State> getTransitionStates() {
+        return mStateDepository;
+    }
+
+    /**
+     * Fetch the reason for network state transition failure
+     * @return the {@link String} for the failure
+     */
+    public String getFailureReason() {
+        return mReason;
+    }
+
+    /**
+     * Print the network state
+     * @return {@link String} representation of the network state
+     */
+    public String printStates() {
+        StringBuilder stateBuilder = new StringBuilder();
+        for (int i = 0; i < mStateDepository.size(); i++) {
+            stateBuilder.append(" ").append(mStateDepository.get(i).toString()).append("->");
+        }
+        return stateBuilder.toString();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("mTransitionDirection: ").append(mTransitionDirection.toString()).
+        append("; ").append("states:").
+        append(printStates()).append("; ");
+        return builder.toString();
+    }
+}
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/BandwidthTestUtil.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/BandwidthTestUtil.java
new file mode 100644
index 0000000..d850169
--- /dev/null
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/BandwidthTestUtil.java
@@ -0,0 +1,109 @@
+/*
+ * 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.bandwidthtest.util;
+
+import android.util.Log;
+
+import org.apache.http.util.ByteArrayBuffer;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.net.URLConnection;
+
+public class BandwidthTestUtil {
+    private static final String LOG_TAG = "BandwidthTestUtil";
+    /**
+     * Parses the first line in a file if exists.
+     *
+     * @param file {@link File} the input
+     * @return the integer value of the first line of the file.
+     */
+    public static int parseIntValueFromFile(File file) {
+        int value = 0;
+        if (file.exists()) {
+            try {
+                FileInputStream fstream = new FileInputStream(file);
+                DataInputStream in = new DataInputStream(fstream);
+                BufferedReader br = new BufferedReader(new InputStreamReader(in));
+                String strLine = br.readLine();
+                if (strLine != null) {
+                    value = Integer.parseInt(strLine);
+                }
+                // Close the input stream
+                in.close();
+            } catch (Exception e) {
+                System.err.println("Error: " + e.getMessage());
+            }
+        }
+        return value;
+    }
+
+    /**
+     * Creates the Download string for the test server.
+     *
+     * @param server url of the test server
+     * @param size in bytes of the file to download
+     * @param deviceId the device id that is downloading
+     * @param timestamp
+     * @return download url
+     */
+    public static String buildDownloadUrl(String server, int size, String deviceId,
+            String timestamp) {
+        String downloadUrl = server + "/download?size=" + size + "&device_id=" + deviceId +
+                "&timestamp=" + timestamp;
+        return downloadUrl;
+    }
+
+    /**
+     * Download a given file from a target url to a given destination file.
+     * @param targetUrl the url to download
+     * @param file the {@link File} location where to save to
+     * @return true if it succeeded.
+     */
+    public static boolean DownloadFromUrl(String targetUrl, File file) {
+        try {
+            URL url = new URL(targetUrl);
+            Log.d(LOG_TAG, "Download begining");
+            Log.d(LOG_TAG, "Download url:" + url);
+            Log.d(LOG_TAG, "Downloaded file name:" + file.getAbsolutePath());
+            URLConnection ucon = url.openConnection();
+            InputStream is = ucon.getInputStream();
+            BufferedInputStream bis = new BufferedInputStream(is);
+            ByteArrayBuffer baf = new ByteArrayBuffer(50);
+            int current = 0;
+            while ((current = bis.read()) != -1) {
+                baf.append((byte) current);
+            }
+            FileOutputStream fos = new FileOutputStream(file);
+            fos.write(baf.toByteArray());
+            fos.close();
+        } catch (IOException e) {
+            Log.d(LOG_TAG, "Failed to download file with error: " + e);
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
new file mode 100644
index 0000000..d663aad
--- /dev/null
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
@@ -0,0 +1,684 @@
+/*
+ * 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.bandwidthtest.util;
+
+import android.app.DownloadManager;
+import android.app.DownloadManager.Query;
+import android.app.DownloadManager.Request;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.Cursor;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.State;
+import android.net.Uri;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.os.Message;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.bandwidthtest.NetworkState;
+import com.android.bandwidthtest.NetworkState.StateTransitionDirection;
+import com.android.internal.util.AsyncChannel;
+
+import java.util.List;
+
+/*
+ * Utility class used to set the connectivity of the device and to download files.
+ */
+public class ConnectionUtil {
+    private static final String LOG_TAG = "ConnectionUtil";
+    private static final String DOWNLOAD_MANAGER_PKG_NAME = "com.android.providers.downloads";
+    private static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; // 10 seconds
+    private static final int WIFI_SCAN_TIMEOUT = 50 * 1000;
+    public static final int SHORT_TIMEOUT = 5 * 1000;
+    public static final int LONG_TIMEOUT = 10 * 1000;
+    private ConnectivityReceiver mConnectivityReceiver = null;
+    private WifiReceiver mWifiReceiver = null;
+    private DownloadReceiver mDownloadReceiver = null;
+    private DownloadManager mDownloadManager;
+    private NetworkInfo mNetworkInfo;
+    private NetworkInfo mOtherNetworkInfo;
+    private boolean mScanResultIsAvailable = false;
+    private ConnectivityManager mCM;
+    private Object mWifiMonitor = new Object();
+    private Object mConnectivityMonitor = new Object();
+    private Object mDownloadMonitor = new Object();
+    private int mWifiState;
+    private NetworkInfo mWifiNetworkInfo;
+    private WifiManager mWifiManager;
+    private Context mContext;
+    // Verify connectivity state
+    private static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE + 1;
+    private NetworkState[] mConnectivityState = new NetworkState[NUM_NETWORK_TYPES];
+
+    public ConnectionUtil(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Initialize the class. Needs to be called before any other methods in {@link ConnectionUtil}
+     *
+     * @throws Exception
+     */
+    public void initialize() throws Exception {
+        // Register a connectivity receiver for CONNECTIVITY_ACTION
+        mConnectivityReceiver = new ConnectivityReceiver();
+        mContext.registerReceiver(mConnectivityReceiver,
+                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
+
+        // Register a download receiver for ACTION_DOWNLOAD_COMPLETE
+        mDownloadReceiver = new DownloadReceiver();
+        mContext.registerReceiver(mDownloadReceiver,
+                new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
+
+        // Register a wifi receiver
+        mWifiReceiver = new WifiReceiver();
+        IntentFilter mIntentFilter = new IntentFilter();
+        mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+        mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
+        mIntentFilter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
+        mContext.registerReceiver(mWifiReceiver, mIntentFilter);
+
+        // Get an instance of ConnectivityManager
+        mCM = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+        // Get an instance of WifiManager
+        mWifiManager =(WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
+        mWifiManager.asyncConnect(mContext, new WifiServiceHandler());
+
+        mDownloadManager = (DownloadManager)mContext.getSystemService(Context.DOWNLOAD_SERVICE);
+
+        initializeNetworkStates();
+
+        mWifiManager.setWifiEnabled(true);
+
+        Log.v(LOG_TAG, "Clear Wifi before we start the test.");
+        sleep(SHORT_TIMEOUT);
+        removeConfiguredNetworksAndDisableWifi();
+    }
+
+
+    /**
+     * A wrapper of a broadcast receiver which provides network connectivity information
+     * for all kinds of network: wifi, mobile, etc.
+     */
+    private class ConnectivityReceiver extends BroadcastReceiver {
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (isInitialStickyBroadcast()) {
+                Log.d(LOG_TAG, "This is a sticky broadcast don't do anything.");
+                return;
+            }
+            Log.v(LOG_TAG, "ConnectivityReceiver: onReceive() is called with " + intent);
+            String action = intent.getAction();
+            if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+                Log.v("ConnectivityReceiver", "onReceive() called with " + intent);
+                return;
+            }
+            if (intent.hasExtra(ConnectivityManager.EXTRA_NETWORK_INFO)) {
+                mNetworkInfo = (NetworkInfo)
+                        intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
+            }
+
+            if (intent.hasExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO)) {
+                mOtherNetworkInfo = (NetworkInfo)
+                        intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
+            }
+
+            Log.v(LOG_TAG, "mNetworkInfo: " + mNetworkInfo.toString());
+            recordNetworkState(mNetworkInfo.getType(), mNetworkInfo.getState());
+            if (mOtherNetworkInfo != null) {
+                Log.v(LOG_TAG, "mOtherNetworkInfo: " + mOtherNetworkInfo.toString());
+                recordNetworkState(mOtherNetworkInfo.getType(), mOtherNetworkInfo.getState());
+            }
+            notifyNetworkConnectivityChange();
+        }
+    }
+
+    /**
+     * A wrapper of a broadcast receiver which provides wifi information.
+     */
+    private class WifiReceiver extends BroadcastReceiver {
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            Log.v("WifiReceiver", "onReceive() is calleld with " + intent);
+            if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
+                Log.v(LOG_TAG, "Scan results are available");
+                notifyScanResult();
+            } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+                mWifiNetworkInfo =
+                        (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
+                Log.v(LOG_TAG, "mWifiNetworkInfo: " + mWifiNetworkInfo.toString());
+                if (mWifiNetworkInfo.getState() == State.CONNECTED) {
+                    intent.getStringExtra(WifiManager.EXTRA_BSSID);
+                }
+                notifyWifiState();
+            } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+                mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+                        WifiManager.WIFI_STATE_UNKNOWN);
+                notifyWifiState();
+            } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
+                notifyWifiAPState();
+            } else {
+                return;
+            }
+        }
+    }
+
+    /**
+     * A wrapper of a broadcast receiver which provides download manager information.
+     */
+    private class DownloadReceiver extends BroadcastReceiver {
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            Log.v("DownloadReceiver", "onReceive() is called with " + intent);
+            // Download complete
+            if (action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
+                notifiyDownloadState();
+            }
+        }
+    }
+
+    private class WifiServiceHandler extends Handler {
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
+                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+                        // AsyncChannel in msg.obj
+                    } else {
+                        Log.v(LOG_TAG, "Failed to establish AsyncChannel connection");
+                    }
+                    break;
+                default:
+                    // Ignore
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Initialize all the network states.
+     */
+    public void initializeNetworkStates() {
+        // For each network type, initialize network states to UNKNOWN, and no verification
+        // flag is set.
+        for (int networkType = NUM_NETWORK_TYPES - 1; networkType >= 0; networkType--) {
+            mConnectivityState[networkType] =  new NetworkState();
+            Log.v(LOG_TAG, "Initialize network state for " + networkType + ": " +
+                    mConnectivityState[networkType].toString());
+        }
+    }
+
+    public void recordNetworkState(int networkType, State networkState) {
+        // deposit a network state
+        Log.v(LOG_TAG, "record network state for network " +  networkType +
+                ", state is " + networkState);
+        mConnectivityState[networkType].recordState(networkState);
+    }
+
+   /**
+    * Set the state transition criteria
+    *
+    * @param networkType
+    * @param initState
+    * @param transitionDir
+    * @param targetState
+    */
+    public void setStateTransitionCriteria(int networkType, State initState,
+            StateTransitionDirection transitionDir, State targetState) {
+        mConnectivityState[networkType].setStateTransitionCriteria(
+                initState, transitionDir, targetState);
+    }
+
+    /**
+     * Validate the states recorded.
+     * @param networkType
+     * @return
+     */
+    public boolean validateNetworkStates(int networkType) {
+        Log.v(LOG_TAG, "validate network state for " + networkType + ": ");
+        return mConnectivityState[networkType].validateStateTransition();
+    }
+
+    /**
+     * Fetch the failure reason for the transition.
+     * @param networkType
+     * @return result from network state validation
+     */
+    public String getTransitionFailureReason(int networkType) {
+        Log.v(LOG_TAG, "get network state transition failure reason for " + networkType + ": " +
+                mConnectivityState[networkType].toString());
+        return mConnectivityState[networkType].getFailureReason();
+    }
+
+    /**
+     * Send a notification via the mConnectivityMonitor when the network connectivity changes.
+     */
+    private void notifyNetworkConnectivityChange() {
+        synchronized(mConnectivityMonitor) {
+            Log.v(LOG_TAG, "notify network connectivity changed");
+            mConnectivityMonitor.notifyAll();
+        }
+    }
+
+    /**
+     * Send a notification when a scan for the wifi network is done.
+     */
+    private void notifyScanResult() {
+        synchronized (this) {
+            Log.v(LOG_TAG, "notify that scan results are available");
+            this.notify();
+        }
+    }
+
+    /**
+     * Send a notification via the mWifiMonitor when the wifi state changes.
+     */
+    private void notifyWifiState() {
+        synchronized (mWifiMonitor) {
+            Log.v(LOG_TAG, "notify wifi state changed.");
+            mWifiMonitor.notify();
+        }
+    }
+
+    /**
+     * Send a notification via the mDownloadMonitor when a download is complete.
+     */
+    private void notifiyDownloadState() {
+        synchronized (mDownloadMonitor) {
+            Log.v(LOG_TAG, "notifiy download manager state changed.");
+            mDownloadMonitor.notify();
+        }
+    }
+
+    /**
+     * Send a notification when the wifi ap state changes.
+     */
+    private void notifyWifiAPState() {
+        synchronized (this) {
+            Log.v(LOG_TAG, "notify wifi AP state changed.");
+            this.notify();
+        }
+    }
+
+    /**
+     * Start a download on a given url and wait for completion.
+     *
+     * @param targetUrl the target to download.x
+     * @param timeout to wait for download to finish
+     * @return true if we successfully downloaded the requestedUrl, false otherwise.
+     */
+    public boolean startDownloadAndWait(String targetUrl, long timeout) {
+        if (targetUrl.length() == 0 || targetUrl == null) {
+            Log.v(LOG_TAG, "Empty or Null target url requested to DownloadManager");
+            return true;
+        }
+        Request request = new Request(Uri.parse(targetUrl));
+        long enqueue = mDownloadManager.enqueue(request);
+        Log.v(LOG_TAG, "Sending download request of " + targetUrl + " to DownloadManager");
+        long startTime = System.currentTimeMillis();
+        while (true) {
+            if ((System.currentTimeMillis() - startTime) > timeout) {
+                Log.v(LOG_TAG, "startDownloadAndWait timed out, failed to fetch " + targetUrl +
+                        " within " + timeout);
+                return downloadSuccessful(enqueue);
+            }
+            Log.v(LOG_TAG, "Waiting for the download to finish " + targetUrl);
+            synchronized (mDownloadMonitor) {
+                try {
+                    mDownloadMonitor.wait(SHORT_TIMEOUT);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                if (!downloadSuccessful(enqueue)) {
+                    continue;
+                }
+                return true;
+            }
+        }
+    }
+
+    /**
+     * Fetch the Download Manager's UID.
+     * @return the Download Manager's UID
+     */
+    public int downloadManagerUid() {
+        try {
+            PackageManager pm = mContext.getPackageManager();
+            ApplicationInfo appInfo = pm.getApplicationInfo(DOWNLOAD_MANAGER_PKG_NAME,
+                    PackageManager.GET_META_DATA);
+            return appInfo.uid;
+        } catch (NameNotFoundException e) {
+            Log.d(LOG_TAG, "Did not find the package for the download service.");
+            return -1;
+        }
+    }
+
+    /**
+     * Determines if a given download was successful by querying the DownloadManager.
+     *
+     * @param enqueue the id used to identify/query the DownloadManager with.
+     * @return true if download was successful, false otherwise.
+     */
+    private boolean downloadSuccessful(long enqueue) {
+        Query query = new Query();
+        query.setFilterById(enqueue);
+        Cursor c = mDownloadManager.query(query);
+        if (c.moveToFirst()) {
+            int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);
+            if (DownloadManager.STATUS_SUCCESSFUL == c.getInt(columnIndex)) {
+                Log.v(LOG_TAG, "Successfully downloaded file!");
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Wait for network connectivity state.
+     * @param networkType the network to check for
+     * @param expectedState the desired state
+     * @param timeout in milliseconds
+     * @return true if the network connectivity state matched what was expected
+     */
+    public boolean waitForNetworkState(int networkType, State expectedState, long timeout) {
+        long startTime = System.currentTimeMillis();
+        while (true) {
+            if ((System.currentTimeMillis() - startTime) > timeout) {
+                Log.v(LOG_TAG, "waitForNetworkState time out, the state of network type " + networkType +
+                        " is: " + mCM.getNetworkInfo(networkType).getState());
+                if (mCM.getNetworkInfo(networkType).getState() != expectedState) {
+                    return false;
+                } else {
+                    // the broadcast has been sent out. the state has been changed.
+                    Log.v(LOG_TAG, "networktype: " + networkType + " state: " +
+                            mCM.getNetworkInfo(networkType));
+                    return true;
+                }
+            }
+            Log.v(LOG_TAG, "Wait for the connectivity state for network: " + networkType +
+                    " to be " + expectedState.toString());
+            synchronized (mConnectivityMonitor) {
+                try {
+                    mConnectivityMonitor.wait(SHORT_TIMEOUT);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                if ((mNetworkInfo.getType() != networkType) ||
+                        (mNetworkInfo.getState() != expectedState)) {
+                    Log.v(LOG_TAG, "network state for " + mNetworkInfo.getType() +
+                            "is: " + mNetworkInfo.getState());
+                    continue;
+                }
+                return true;
+            }
+        }
+    }
+
+    /**
+     * Wait for a given wifi state to occur within a given timeout.
+     * @param expectedState the expected wifi state.
+     * @param timeout for the state to be set in milliseconds.
+     * @return true if the state was achieved within the timeout, false otherwise.
+     */
+    public boolean waitForWifiState(int expectedState, long timeout) {
+        // Wait for Wifi state: WIFI_STATE_DISABLED, WIFI_STATE_DISABLING, WIFI_STATE_ENABLED,
+        //                      WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN
+        long startTime = System.currentTimeMillis();
+        while (true) {
+            if ((System.currentTimeMillis() - startTime) > timeout) {
+                if (mWifiState != expectedState) {
+                    return false;
+                } else {
+                    return true;
+                }
+            }
+            Log.v(LOG_TAG, "Wait for wifi state to be: " + expectedState);
+            synchronized (mWifiMonitor) {
+                try {
+                    mWifiMonitor.wait(SHORT_TIMEOUT);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                if (mWifiState != expectedState) {
+                    Log.v(LOG_TAG, "Wifi state is: " + mWifiState);
+                    continue;
+                }
+                return true;
+            }
+        }
+    }
+
+    /**
+     * Convenience method to determine if we are connected to a mobile network.
+     * @return true if connected to a mobile network, false otherwise.
+     */
+    public boolean isConnectedToMobile() {
+        return (mNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE);
+    }
+
+    /**
+     * Convenience method to determine if we are connected to wifi.
+     * @return true if connected to wifi, false otherwise.
+     */
+    public boolean isConnectedToWifi() {
+        return (mNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI);
+    }
+
+
+    /**
+     * Associate the device to given SSID
+     * If the device is already associated with a WiFi, disconnect and forget it,
+     * We don't verify whether the connection is successful or not, leave this to the test
+     */
+    public boolean connectToWifi(String knownSSID) {
+        WifiConfiguration config = new WifiConfiguration();
+        config.SSID = knownSSID;
+        config.allowedKeyManagement.set(KeyMgmt.NONE);
+        return connectToWifiWithConfiguration(config);
+    }
+
+    /**
+     * Connect to Wi-Fi with the given configuration.
+     * @param config
+     * @return true if we ar connected to a given
+     */
+    public boolean connectToWifiWithConfiguration(WifiConfiguration config) {
+        //  The SSID in the configuration is a pure string, need to convert it to a quoted string.
+        String ssid = config.SSID;
+        config.SSID = convertToQuotedString(ssid);
+
+        // If wifi is not enabled, enable it
+        if (!mWifiManager.isWifiEnabled()) {
+            Log.v(LOG_TAG, "Wifi is not enabled, enable it");
+            mWifiManager.setWifiEnabled(true);
+            // wait for the wifi state change before start scanning.
+            if (!waitForWifiState(WifiManager.WIFI_STATE_ENABLED, 2 * SHORT_TIMEOUT)) {
+                Log.v(LOG_TAG, "Wait for WIFI_STATE_ENABLED failed");
+                return false;
+            }
+        }
+
+        boolean foundApInScanResults = false;
+        for (int retry = 0; retry < 5; retry++) {
+            List<ScanResult> netList = mWifiManager.getScanResults();
+            if (netList != null) {
+                Log.v(LOG_TAG, "size of scan result list: " + netList.size());
+                for (int i = 0; i < netList.size(); i++) {
+                    ScanResult sr= netList.get(i);
+                    if (sr.SSID.equals(ssid)) {
+                        Log.v(LOG_TAG, "Found " + ssid + " in the scan result list.");
+                        Log.v(LOG_TAG, "Retry: " + retry);
+                        foundApInScanResults = true;
+                        mWifiManager.connectNetwork(config);
+                        break;
+                    }
+                }
+            }
+            if (foundApInScanResults) {
+                return true;
+            } else {
+                // Start an active scan
+                mWifiManager.startScanActive();
+                mScanResultIsAvailable = false;
+                long startTime = System.currentTimeMillis();
+                while (!mScanResultIsAvailable) {
+                    if ((System.currentTimeMillis() - startTime) > WIFI_SCAN_TIMEOUT) {
+                        Log.v(LOG_TAG, "wait for scan results timeout");
+                        return false;
+                    }
+                    // wait for the scan results to be available
+                    synchronized (this) {
+                        // wait for the scan result to be available
+                        try {
+                            this.wait(WAIT_FOR_SCAN_RESULT);
+                        } catch (InterruptedException e) {
+                            e.printStackTrace();
+                        }
+                        if ((mWifiManager.getScanResults() == null) ||
+                                (mWifiManager.getScanResults().size() <= 0)) {
+                            continue;
+                        }
+                        mScanResultIsAvailable = true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /*
+     * Disconnect from the current AP and remove configured networks.
+     */
+    public boolean disconnectAP() {
+        // remove saved networks
+        List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks();
+        Log.v(LOG_TAG, "size of wifiConfigList: " + wifiConfigList.size());
+        for (WifiConfiguration wifiConfig: wifiConfigList) {
+            Log.v(LOG_TAG, "Remove wifi configuration: " + wifiConfig.networkId);
+            int netId = wifiConfig.networkId;
+            mWifiManager.forgetNetwork(netId);
+        }
+        return true;
+    }
+
+    /**
+     * Enable Wifi
+     * @return true if Wifi is enabled successfully
+     */
+    public boolean enableWifi() {
+        return mWifiManager.setWifiEnabled(true);
+    }
+
+    /**
+     * Disable Wifi
+     * @return true if Wifi is disabled successfully
+     */
+    public boolean disableWifi() {
+        return mWifiManager.setWifiEnabled(false);
+    }
+
+    /**
+     * Remove configured networks and disable wifi
+     */
+    public boolean removeConfiguredNetworksAndDisableWifi() {
+        if (!disconnectAP()) {
+            return false;
+        }
+        sleep(SHORT_TIMEOUT);
+        if (!mWifiManager.setWifiEnabled(false)) {
+            return false;
+        }
+        sleep(SHORT_TIMEOUT);
+        return true;
+    }
+
+    /**
+     * Make the current thread sleep.
+     * @param sleeptime the time to sleep in milliseconds
+     */
+    private void sleep(long sleeptime) {
+        try {
+            Thread.sleep(sleeptime);
+        } catch (InterruptedException e) {}
+    }
+
+    /**
+     * Set airplane mode on device, caller is responsible to ensuring correct state.
+     * @param context {@link Context}
+     * @param enableAM to enable or disable airplane mode.
+     */
+    public void setAirplaneMode(Context context, boolean enableAM) {
+        //set the airplane mode
+        Settings.System.putInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON,
+                enableAM ? 1 : 0);
+        // Post the intent
+        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        intent.putExtra("state", enableAM);
+        context.sendBroadcast(intent);
+    }
+
+    /**
+     * Add quotes around the string.
+     * @param string to convert
+     * @return string with quotes around it
+     */
+    protected static String convertToQuotedString(String string) {
+        return "\"" + string + "\"";
+    }
+
+    public void cleanUp() {
+        // Unregister receivers if defined.
+        if (mConnectivityReceiver != null) {
+            mContext.unregisterReceiver(mConnectivityReceiver);
+        }
+        if (mWifiReceiver != null) {
+            mContext.unregisterReceiver(mWifiReceiver);
+        }
+        if (mDownloadReceiver != null) {
+            mContext.unregisterReceiver(mDownloadReceiver);
+        }
+        Log.v(LOG_TAG, "onDestroy, inst=" + Integer.toHexString(hashCode()));
+    }
+}
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/animation/EventsTest.java b/core/tests/coretests/src/android/animation/EventsTest.java
index f970ffc..6ea2845 100644
--- a/core/tests/coretests/src/android/animation/EventsTest.java
+++ b/core/tests/coretests/src/android/animation/EventsTest.java
@@ -21,6 +21,8 @@
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import java.util.concurrent.TimeUnit;
+
 /**
  * Tests for the various lifecycle events of Animators. This abstract class is subclassed by
  * concrete implementations that provide the actual Animator objects being tested. All of the
@@ -40,7 +42,10 @@
     private static final int ANIM_DELAY = 100;
     private static final int ANIM_MID_DURATION = ANIM_DURATION / 2;
     private static final int ANIM_MID_DELAY = ANIM_DELAY / 2;
+    private static final int FUTURE_RELEASE_DELAY = 50;
+    private static final int TIMEOUT = ANIM_DURATION + ANIM_DELAY + FUTURE_RELEASE_DELAY;
 
+    private boolean mStarted;  // tracks whether we've received the onAnimationStart() callback
     private boolean mRunning;  // tracks whether we've started the animator
     private boolean mCanceled; // trackes whether we've canceled the animator
     private Animator.AnimatorListener mFutureListener; // mechanism for delaying the end of the test
@@ -51,17 +56,44 @@
                                   // setup() method prior to calling the superclass setup()
 
     /**
-     * Cancels the given animator. Used to delay cancelation until some later time (after the
+     * Cancels the given animator. Used to delay cancellation until some later time (after the
      * animator has started playing).
      */
     static class Canceler implements Runnable {
         Animator mAnim;
-        public Canceler(Animator anim) {
+        FutureWaiter mFuture;
+        public Canceler(Animator anim, FutureWaiter future) {
             mAnim = anim;
+            mFuture = future;
         }
         @Override
         public void run() {
-            mAnim.cancel();
+            try {
+                mAnim.cancel();
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
+            }
+        }
+    };
+
+    /**
+     * Ends the given animator. Used to delay ending until some later time (after the
+     * animator has started playing).
+     */
+    static class Ender implements Runnable {
+        Animator mAnim;
+        FutureWaiter mFuture;
+        public Ender(Animator anim, FutureWaiter future) {
+            mAnim = anim;
+            mFuture = future;
+        }
+        @Override
+        public void run() {
+            try {
+                mAnim.end();
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
+            }
         }
     };
 
@@ -76,6 +108,23 @@
         public FutureReleaseListener(FutureWaiter future) {
             mFuture = future;
         }
+
+        /**
+         * Variant constructor that auto-releases the FutureWaiter after the specified timeout.
+         * @param future
+         * @param timeout
+         */
+        public FutureReleaseListener(FutureWaiter future, long timeout) {
+            mFuture = future;
+            Handler handler = new Handler();
+            handler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    mFuture.release();
+                }
+            }, timeout);
+        }
+
         @Override
         public void onAnimationEnd(Animator animation) {
             Handler handler = new Handler();
@@ -84,7 +133,7 @@
                 public void run() {
                     mFuture.release();
                 }
-            }, ANIM_MID_DURATION);
+            }, FUTURE_RELEASE_DELAY);
         }
     };
 
@@ -92,7 +141,6 @@
         super(BasicAnimatorActivity.class);
     }
 
-
     /**
      * Sets up the fields used by each test. Subclasses must override this method to create
      * the protected mAnimator object used in all tests. Overrides must create that animator
@@ -107,11 +155,20 @@
         // are embedded in the listener callbacks that it implements.
         mListener = new AnimatorListenerAdapter() {
             @Override
+            public void onAnimationStart(Animator animation) {
+                // This should only be called on an animation that has not yet been started
+                assertFalse(mStarted);
+                assertTrue(mRunning);
+                mStarted = true;
+            }
+
+            @Override
             public void onAnimationCancel(Animator animation) {
                 // This should only be called on an animation that has been started and not
                 // yet canceled or ended
                 assertFalse(mCanceled);
                 assertTrue(mRunning);
+                assertTrue(mStarted);
                 mCanceled = true;
             }
 
@@ -120,7 +177,9 @@
                 // This should only be called on an animation that has been started and not
                 // yet ended
                 assertTrue(mRunning);
+                assertTrue(mStarted);
                 mRunning = false;
+                mStarted = false;
                 super.onAnimationEnd(animation);
             }
         };
@@ -132,6 +191,7 @@
 
         mRunning = false;
         mCanceled = false;
+        mStarted = false;
     }
 
     /**
@@ -144,26 +204,104 @@
     }
 
     /**
+     * Verify that calling end on an unstarted animator does nothing.
+     */
+    @UiThreadTest
+    @SmallTest
+    public void testEnd() throws Exception {
+        mAnimator.end();
+    }
+
+    /**
      * Verify that calling cancel on a started animator does the right thing.
      */
     @UiThreadTest
     @SmallTest
     public void testStartCancel() throws Exception {
-        mRunning = true;
-        mAnimator.start();
-        mAnimator.cancel();
+        mFutureListener = new FutureReleaseListener(mFuture);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    mRunning = true;
+                    mAnimator.start();
+                    mAnimator.cancel();
+                    mFuture.release();
+                } catch (junit.framework.AssertionFailedError e) {
+                    mFuture.setException(new RuntimeException(e));
+                }
+            }
+        });
+        mFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Verify that calling end on a started animator does the right thing.
+     */
+    @UiThreadTest
+    @SmallTest
+    public void testStartEnd() throws Exception {
+        mFutureListener = new FutureReleaseListener(mFuture);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    mRunning = true;
+                    mAnimator.start();
+                    mAnimator.end();
+                    mFuture.release();
+                } catch (junit.framework.AssertionFailedError e) {
+                    mFuture.setException(new RuntimeException(e));
+                }
+            }
+        });
+        mFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
     }
 
     /**
      * Same as testStartCancel, but with a startDelayed animator
      */
-    @UiThreadTest
     @SmallTest
     public void testStartDelayedCancel() throws Exception {
+        mFutureListener = new FutureReleaseListener(mFuture);
         mAnimator.setStartDelay(ANIM_DELAY);
-        mRunning = true;
-        mAnimator.start();
-        mAnimator.cancel();
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    mRunning = true;
+                    mAnimator.start();
+                    mAnimator.cancel();
+                    mFuture.release();
+                } catch (junit.framework.AssertionFailedError e) {
+                    mFuture.setException(new RuntimeException(e));
+                }
+            }
+        });
+        mFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Same as testStartEnd, but with a startDelayed animator
+     */
+    @SmallTest
+    public void testStartDelayedEnd() throws Exception {
+        mFutureListener = new FutureReleaseListener(mFuture);
+        mAnimator.setStartDelay(ANIM_DELAY);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    mRunning = true;
+                    mAnimator.start();
+                    mAnimator.end();
+                    mFuture.release();
+                } catch (junit.framework.AssertionFailedError e) {
+                    mFuture.setException(new RuntimeException(e));
+                }
+            }
+        });
+        mFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
     }
 
     /**
@@ -180,13 +318,36 @@
                     mAnimator.addListener(mFutureListener);
                     mRunning = true;
                     mAnimator.start();
-                    handler.postDelayed(new Canceler(mAnimator), ANIM_MID_DURATION);
+                    handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DURATION);
                 } catch (junit.framework.AssertionFailedError e) {
                     mFuture.setException(new RuntimeException(e));
                 }
             }
         });
-        mFuture.get();
+        mFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Verify that ending an animator that is playing does the right thing.
+     */
+    @MediumTest
+    public void testPlayingEnd() throws Exception {
+        mFutureListener = new FutureReleaseListener(mFuture);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    Handler handler = new Handler();
+                    mAnimator.addListener(mFutureListener);
+                    mRunning = true;
+                    mAnimator.start();
+                    handler.postDelayed(new Ender(mAnimator, mFuture), ANIM_MID_DURATION);
+                } catch (junit.framework.AssertionFailedError e) {
+                    mFuture.setException(new RuntimeException(e));
+                }
+            }
+        });
+        mFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
     }
 
     /**
@@ -204,13 +365,91 @@
                     mAnimator.addListener(mFutureListener);
                     mRunning = true;
                     mAnimator.start();
-                    handler.postDelayed(new Canceler(mAnimator), ANIM_MID_DURATION);
+                    handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DURATION);
                 } catch (junit.framework.AssertionFailedError e) {
                     mFuture.setException(new RuntimeException(e));
                 }
             }
         });
-        mFuture.get();
+        mFuture.get(TIMEOUT,  TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Same as testPlayingEnd, but with a startDelayed animator
+     */
+    @MediumTest
+    public void testPlayingDelayedEnd() throws Exception {
+        mAnimator.setStartDelay(ANIM_DELAY);
+        mFutureListener = new FutureReleaseListener(mFuture);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    Handler handler = new Handler();
+                    mAnimator.addListener(mFutureListener);
+                    mRunning = true;
+                    mAnimator.start();
+                    handler.postDelayed(new Ender(mAnimator, mFuture), ANIM_MID_DURATION);
+                } catch (junit.framework.AssertionFailedError e) {
+                    mFuture.setException(new RuntimeException(e));
+                }
+            }
+        });
+        mFuture.get(TIMEOUT,  TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Same as testPlayingDelayedCancel, but cancel during the startDelay period
+     */
+    @MediumTest
+    public void testPlayingDelayedCancelMidDelay() throws Exception {
+        mAnimator.setStartDelay(ANIM_DELAY);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    // Set the listener to automatically timeout after an uncanceled animation
+                    // would have finished. This tests to make sure that we're not calling
+                    // the listeners with cancel/end callbacks since they won't be called
+                    // with the start event.
+                    mFutureListener = new FutureReleaseListener(mFuture, TIMEOUT);
+                    Handler handler = new Handler();
+                    mRunning = true;
+                    mAnimator.start();
+                    handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DELAY);
+                } catch (junit.framework.AssertionFailedError e) {
+                    mFuture.setException(new RuntimeException(e));
+                }
+            }
+        });
+        mFuture.get(TIMEOUT + 100,  TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Same as testPlayingDelayedEnd, but end during the startDelay period
+     */
+    @MediumTest
+    public void testPlayingDelayedEndMidDelay() throws Exception {
+        mAnimator.setStartDelay(ANIM_DELAY);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    // Set the listener to automatically timeout after an uncanceled animation
+                    // would have finished. This tests to make sure that we're not calling
+                    // the listeners with cancel/end callbacks since they won't be called
+                    // with the start event.
+                    mFutureListener = new FutureReleaseListener(mFuture, TIMEOUT);
+                    Handler handler = new Handler();
+                    mRunning = true;
+                    mAnimator.start();
+                    handler.postDelayed(new Ender(mAnimator, mFuture), ANIM_MID_DELAY);
+                } catch (junit.framework.AssertionFailedError e) {
+                    mFuture.setException(new RuntimeException(e));
+                }
+            }
+        });
+        mFuture.get(TIMEOUT + 100,  TimeUnit.MILLISECONDS);
     }
 
     /**
@@ -234,7 +473,31 @@
                 }
             }
         });
-        mFuture.get();
+        mFuture.get(TIMEOUT,  TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Verifies that ending a started animation after it has already been ended
+     * does nothing.
+     */
+    @MediumTest
+    public void testStartDoubleEnd() throws Exception {
+        mFutureListener = new FutureReleaseListener(mFuture);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    mRunning = true;
+                    mAnimator.start();
+                    mAnimator.end();
+                    mAnimator.end();
+                    mFuture.release();
+                } catch (junit.framework.AssertionFailedError e) {
+                    mFuture.setException(new RuntimeException(e));
+                }
+            }
+        });
+        mFuture.get(TIMEOUT,  TimeUnit.MILLISECONDS);
     }
 
     /**
@@ -258,8 +521,31 @@
                 }
             }
         });
-        mFuture.get();
-    }
+        mFuture.get(TIMEOUT,  TimeUnit.MILLISECONDS);
+     }
 
+    /**
+     * Same as testStartDoubleEnd, but with a startDelayed animator
+     */
+    @MediumTest
+    public void testStartDelayedDoubleEnd() throws Exception {
+        mAnimator.setStartDelay(ANIM_DELAY);
+        mFutureListener = new FutureReleaseListener(mFuture);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    mRunning = true;
+                    mAnimator.start();
+                    mAnimator.end();
+                    mAnimator.end();
+                    mFuture.release();
+                } catch (junit.framework.AssertionFailedError e) {
+                    mFuture.setException(new RuntimeException(e));
+                }
+            }
+        });
+        mFuture.get(TIMEOUT,  TimeUnit.MILLISECONDS);
+     }
 
 }
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 5d28ef7..6c87c3b 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -3114,6 +3114,13 @@
                 PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
     }
 
+    @LargeTest
+    public void testInstallNonexistentFile() {
+        int retCode = PackageManager.INSTALL_FAILED_INVALID_URI;
+        File invalidFile = new File("/nonexistent-file.apk");
+        invokeInstallPackageFail(Uri.fromFile(invalidFile), 0, retCode);
+    }
+
     /*---------- Recommended install location tests ----*/
     /*
      * TODO's
diff --git a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
index 242057c..4db4ea5 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
@@ -16,6 +16,14 @@
 
 package android.net;
 
+import static android.net.NetworkStatsHistory.FIELD_ALL;
+import static android.net.NetworkStatsHistory.FIELD_OPERATIONS;
+import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
+import static android.net.NetworkStatsHistory.FIELD_RX_PACKETS;
+import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
+import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLong;
+import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLong;
+import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
@@ -30,7 +38,10 @@
 
 import com.android.frameworks.coretests.R;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
+import java.io.DataOutputStream;
 import java.util.Random;
 
 @SmallTest
@@ -39,6 +50,10 @@
 
     private static final long TEST_START = 1194220800000L;
 
+    private static final long KB_IN_BYTES = 1024;
+    private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
+    private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
+
     private NetworkStatsHistory stats;
 
     @Override
@@ -80,10 +95,11 @@
         stats = new NetworkStatsHistory(BUCKET_SIZE);
 
         // record data into narrow window to get single bucket
-        stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 1024L, 2048L);
+        stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
+                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
 
         assertEquals(1, stats.size());
-        assertValues(stats, 0, 1024L, 2048L);
+        assertValues(stats, 0, 1024L, 10L, 2048L, 20L, 2L);
     }
 
     public void testRecordEqualBuckets() throws Exception {
@@ -92,11 +108,12 @@
 
         // split equally across two buckets
         final long recordStart = TEST_START + (bucketDuration / 2);
-        stats.recordData(recordStart, recordStart + bucketDuration, 1024L, 128L);
+        stats.recordData(recordStart, recordStart + bucketDuration,
+                new NetworkStats.Entry(1024L, 10L, 128L, 2L, 2L));
 
         assertEquals(2, stats.size());
-        assertValues(stats, 0, 512L, 64L);
-        assertValues(stats, 1, 512L, 64L);
+        assertValues(stats, 0, 512L, 5L, 64L, 1L, 1L);
+        assertValues(stats, 1, 512L, 5L, 64L, 1L, 1L);
     }
 
     public void testRecordTouchingBuckets() throws Exception {
@@ -107,15 +124,16 @@
         // overlap into neighboring buckets. total record is 20 minutes.
         final long recordStart = (TEST_START + BUCKET_SIZE) - MINUTE_IN_MILLIS;
         final long recordEnd = (TEST_START + (BUCKET_SIZE * 2)) + (MINUTE_IN_MILLIS * 4);
-        stats.recordData(recordStart, recordEnd, 1000L, 5000L);
+        stats.recordData(recordStart, recordEnd,
+                new NetworkStats.Entry(1000L, 2000L, 5000L, 10000L, 100L));
 
         assertEquals(3, stats.size());
         // first bucket should have (1/20 of value)
-        assertValues(stats, 0, 50L, 250L);
+        assertValues(stats, 0, 50L, 100L, 250L, 500L, 5L);
         // second bucket should have (15/20 of value)
-        assertValues(stats, 1, 750L, 3750L);
+        assertValues(stats, 1, 750L, 1500L, 3750L, 7500L, 75L);
         // final bucket should have (4/20 of value)
-        assertValues(stats, 2, 200L, 1000L);
+        assertValues(stats, 2, 200L, 400L, 1000L, 2000L, 20L);
     }
 
     public void testRecordGapBuckets() throws Exception {
@@ -125,25 +143,28 @@
         // record some data today and next week with large gap
         final long firstStart = TEST_START;
         final long lastStart = TEST_START + WEEK_IN_MILLIS;
-        stats.recordData(firstStart, firstStart + SECOND_IN_MILLIS, 128L, 256L);
-        stats.recordData(lastStart, lastStart + SECOND_IN_MILLIS, 64L, 512L);
+        stats.recordData(firstStart, firstStart + SECOND_IN_MILLIS,
+                new NetworkStats.Entry(128L, 2L, 256L, 4L, 1L));
+        stats.recordData(lastStart, lastStart + SECOND_IN_MILLIS,
+                new NetworkStats.Entry(64L, 1L, 512L, 8L, 2L));
 
         // we should have two buckets, far apart from each other
         assertEquals(2, stats.size());
-        assertValues(stats, 0, 128L, 256L);
-        assertValues(stats, 1, 64L, 512L);
+        assertValues(stats, 0, 128L, 2L, 256L, 4L, 1L);
+        assertValues(stats, 1, 64L, 1L, 512L, 8L, 2L);
 
         // now record something in middle, spread across two buckets
         final long middleStart = TEST_START + DAY_IN_MILLIS;
         final long middleEnd = middleStart + (HOUR_IN_MILLIS * 2);
-        stats.recordData(middleStart, middleEnd, 2048L, 2048L);
+        stats.recordData(middleStart, middleEnd,
+                new NetworkStats.Entry(2048L, 4L, 2048L, 4L, 2L));
 
         // now should have four buckets, with new record in middle two buckets
         assertEquals(4, stats.size());
-        assertValues(stats, 0, 128L, 256L);
-        assertValues(stats, 1, 1024L, 1024L);
-        assertValues(stats, 2, 1024L, 1024L);
-        assertValues(stats, 3, 64L, 512L);
+        assertValues(stats, 0, 128L, 2L, 256L, 4L, 1L);
+        assertValues(stats, 1, 1024L, 2L, 1024L, 2L, 1L);
+        assertValues(stats, 2, 1024L, 2L, 1024L, 2L, 1L);
+        assertValues(stats, 3, 64L, 1L, 512L, 8L, 2L);
     }
 
     public void testRecordOverlapBuckets() throws Exception {
@@ -151,14 +172,16 @@
         stats = new NetworkStatsHistory(BUCKET_SIZE);
 
         // record some data in one bucket, and another overlapping buckets
-        stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 256L, 256L);
+        stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
+                new NetworkStats.Entry(256L, 2L, 256L, 2L, 1L));
         final long midStart = TEST_START + (HOUR_IN_MILLIS / 2);
-        stats.recordData(midStart, midStart + HOUR_IN_MILLIS, 1024L, 1024L);
+        stats.recordData(midStart, midStart + HOUR_IN_MILLIS,
+                new NetworkStats.Entry(1024L, 10L, 1024L, 10L, 10L));
 
         // should have two buckets, with some data mixed together
         assertEquals(2, stats.size());
-        assertValues(stats, 0, 768L, 768L);
-        assertValues(stats, 1, 512L, 512L);
+        assertValues(stats, 0, 768L, 7L, 768L, 7L, 6L);
+        assertValues(stats, 1, 512L, 5L, 512L, 5L, 5L);
     }
 
     public void testRecordEntireGapIdentical() throws Exception {
@@ -283,6 +306,7 @@
     public void testFuzzing() throws Exception {
         try {
             // fuzzing with random events, looking for crashes
+            final NetworkStats.Entry entry = new NetworkStats.Entry();
             final Random r = new Random();
             for (int i = 0; i < 500; i++) {
                 stats = new NetworkStatsHistory(r.nextLong());
@@ -291,7 +315,12 @@
                         // add range
                         final long start = r.nextLong();
                         final long end = start + r.nextInt();
-                        stats.recordData(start, end, r.nextLong(), r.nextLong());
+                        entry.rxBytes = nextPositiveLong(r);
+                        entry.rxPackets = nextPositiveLong(r);
+                        entry.txBytes = nextPositiveLong(r);
+                        entry.txPackets = nextPositiveLong(r);
+                        entry.operations = nextPositiveLong(r);
+                        stats.recordData(start, end, entry);
                     } else {
                         // trim something
                         stats.removeBucketsBefore(r.nextLong());
@@ -305,6 +334,88 @@
         }
     }
 
+    private static long nextPositiveLong(Random r) {
+        final long value = r.nextLong();
+        return value < 0 ? -value : value;
+    }
+
+    public void testIgnoreFields() throws Exception {
+        final NetworkStatsHistory history = new NetworkStatsHistory(
+                MINUTE_IN_MILLIS, 0, FIELD_RX_BYTES | FIELD_TX_BYTES);
+
+        history.recordData(0, MINUTE_IN_MILLIS,
+                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
+        history.recordData(0, MINUTE_IN_MILLIS * 2,
+                new NetworkStats.Entry(2L, 2L, 2L, 2L, 2L));
+
+        assertValues(
+                history, Long.MIN_VALUE, Long.MAX_VALUE, 1026L, UNKNOWN, 2050L, UNKNOWN, UNKNOWN);
+    }
+
+    public void testIgnoreFieldsRecordIn() throws Exception {
+        final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
+        final NetworkStatsHistory partial = new NetworkStatsHistory(
+                MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
+
+        full.recordData(0, MINUTE_IN_MILLIS,
+                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
+        partial.recordEntireHistory(full);
+
+        assertValues(partial, Long.MIN_VALUE, Long.MAX_VALUE, UNKNOWN, 10L, UNKNOWN, UNKNOWN, 4L);
+    }
+
+    public void testIgnoreFieldsRecordOut() throws Exception {
+        final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
+        final NetworkStatsHistory partial = new NetworkStatsHistory(
+                MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
+
+        partial.recordData(0, MINUTE_IN_MILLIS,
+                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
+        full.recordEntireHistory(partial);
+
+        assertValues(full, Long.MIN_VALUE, Long.MAX_VALUE, 0L, 10L, 0L, 0L, 4L);
+    }
+
+    public void testSerialize() throws Exception {
+        final NetworkStatsHistory before = new NetworkStatsHistory(MINUTE_IN_MILLIS, 40, FIELD_ALL);
+        before.recordData(0, MINUTE_IN_MILLIS * 4,
+                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
+        before.recordData(DAY_IN_MILLIS, DAY_IN_MILLIS + MINUTE_IN_MILLIS,
+                new NetworkStats.Entry(10L, 20L, 30L, 40L, 50L));
+
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        before.writeToStream(new DataOutputStream(out));
+        out.close();
+
+        final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+        final NetworkStatsHistory after = new NetworkStatsHistory(new DataInputStream(in));
+
+        // must have identical totals before and after
+        assertValues(before, Long.MIN_VALUE, Long.MAX_VALUE, 1034L, 30L, 2078L, 60L, 54L);
+        assertValues(after, Long.MIN_VALUE, Long.MAX_VALUE, 1034L, 30L, 2078L, 60L, 54L);
+    }
+
+    public void testVarLong() throws Exception {
+        assertEquals(0L, performVarLong(0L));
+        assertEquals(-1L, performVarLong(-1L));
+        assertEquals(1024L, performVarLong(1024L));
+        assertEquals(-1024L, performVarLong(-1024L));
+        assertEquals(40 * MB_IN_BYTES, performVarLong(40 * MB_IN_BYTES));
+        assertEquals(512 * GB_IN_BYTES, performVarLong(512 * GB_IN_BYTES));
+        assertEquals(Long.MIN_VALUE, performVarLong(Long.MIN_VALUE));
+        assertEquals(Long.MAX_VALUE, performVarLong(Long.MAX_VALUE));
+        assertEquals(Long.MIN_VALUE + 40, performVarLong(Long.MIN_VALUE + 40));
+        assertEquals(Long.MAX_VALUE - 40, performVarLong(Long.MAX_VALUE - 40));
+    }
+
+    private static long performVarLong(long before) throws Exception {
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        writeVarLong(new DataOutputStream(out), before);
+
+        final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+        return readVarLong(new DataInputStream(in));
+    }
+
     private static void assertConsistent(NetworkStatsHistory stats) {
         // verify timestamps are monotonic
         long lastStart = Long.MIN_VALUE;
@@ -330,4 +441,23 @@
         assertEquals("unexpected txBytes", txBytes, entry.txBytes);
     }
 
+    private static void assertValues(NetworkStatsHistory stats, int index, long rxBytes,
+            long rxPackets, long txBytes, long txPackets, long operations) {
+        final NetworkStatsHistory.Entry entry = stats.getValues(index, null);
+        assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
+        assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
+        assertEquals("unexpected txBytes", txBytes, entry.txBytes);
+        assertEquals("unexpected txPackets", txPackets, entry.txPackets);
+        assertEquals("unexpected operations", operations, entry.operations);
+    }
+
+    private static void assertValues(NetworkStatsHistory stats, long start, long end, long rxBytes,
+            long rxPackets, long txBytes, long txPackets, long operations) {
+        final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
+        assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
+        assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
+        assertEquals("unexpected txBytes", txBytes, entry.txBytes);
+        assertEquals("unexpected txPackets", txPackets, entry.txPackets);
+        assertEquals("unexpected operations", operations, entry.operations);
+    }
 }
diff --git a/docs/html/guide/developing/tools/draw9patch.jd b/docs/html/guide/developing/tools/draw9patch.jd
index 1d9de4f..7cf0e4b 100644
--- a/docs/html/guide/developing/tools/draw9patch.jd
+++ b/docs/html/guide/developing/tools/draw9patch.jd
@@ -41,7 +41,7 @@
      A previously saved 9-patch file (<code>*.9.png</code>) will be loaded as-is, 
      with no drawing area added, because it already exists.</p>
 
-<img src="{@docRoot}images/draw9patch-bad.png" style="float:right" alt="" height="300" width="341"
+<img src="{@docRoot}images/draw9patch-bad.png" style="float:right;clear:both" alt="" height="300" width="341"
 />
 
 <p>Optional controls include:</p>
diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd
index ef98a6a..49d6b62 100644
--- a/docs/html/guide/topics/manifest/uses-feature-element.jd
+++ b/docs/html/guide/topics/manifest/uses-feature-element.jd
@@ -677,20 +677,36 @@
   <td>The application uses basic touch interaction events, such as "click down", "click
 up", and drag.</td>
   <td>When declared, this indicates that the application is compatible with a device that offers an
-emulated touchscreen (or better). A device that offers an emulated touchscreen provides a user input
-system that can emulate a subset of touchscreen capabilities. An example of such an input system is
-a mouse or remote control that drives an on-screen cursor. If your application does not require
-complicated gestures and you want your application available to devices that use an on-screen
-cursor to emulate touch events, you should declare this feature.</td>
+emulated touchscreen ("fake touch" interface), or better. A device that offers a fake touch 
+interface provides a user input system that emulates a subset of touchscreen capabilities. For
+example, a mouse or remote control that drives an on-screen cursor provides a fake touch interface.
+If your application requires only basic point and click interaction, you should declare this
+feature. Because this is the minimum level of touch interaction, your app will also be compatible
+with devices that offer more complex touch interfaces.
+  <p class="note"><strong>Note:</strong> Because applications require the {@code
+android.hardware.touchscreen} feature by default, if you want your application to be available to
+devices that provide a fake touch interface, you must also explicitly declare that a touch screen is
+<em>not</em> required by declaring {@code &lt;uses-feature
+android:name="android.hardware.touchscreen" <strong>android:required="false"</strong>
+/&gt;}</p></td>
 </tr>
 <tr>
   <td><code>android.hardware.touchscreen</code></td>
-  <td>The application uses touchscreen capabilities, for gestures more interactive
-than basic touches, such as a fling. This is a superset of the faketouch features.</td>
-  <td>By default, this is assumed to be required, unless you declare
-<code>android.hardware.faketouch</code> (the subset touch mode). As such, your application is
-<em>not</em> available to devices that provide only an emulated touch interface ("fake touch") by
-default.</td>
+  <td>The application uses touchscreen capabilities for gestures that are more interactive
+than basic touch events, such as a fling. This is a superset of the faketouch features.</td>
+  <td>By default, your application requires this. As such, your application is
+<em>not</em> available to devices that provide only an emulated touch interface ("fake touch"), by
+default. If you want your application available to devices that provide a fake touch interface,
+you must explicitly declare that a touch screen is not required, by
+declaring {@code android.hardware.touchscreen} with {@code android:required="false"}. You should
+do so even if your application uses&mdash;but does not <em>require</em>&mdash;a real touch screen
+interface.
+<p>If your application <em>does require</em> a basic touch interface (in order to perform touch
+gestures such as a fling), then you don't need to do anything, because this is required by default.
+However, it's best if you explicitly declare all features used by your application, so you should
+still declare this if your app uses it.</p>
+  <p>If you require more complex touch interaction, such as multi-finger gestures, you
+should declare the advanced touch screen features below.</p></td>
 </tr>
 <tr>
   <td><code>android.hardware.touchscreen.multitouch</code></td>
diff --git a/drm/libdrmframework/plugins/common/util/include/SessionMap.h b/drm/libdrmframework/plugins/common/util/include/SessionMap.h
index 3dff58c..e563894 100644
--- a/drm/libdrmframework/plugins/common/util/include/SessionMap.h
+++ b/drm/libdrmframework/plugins/common/util/include/SessionMap.h
@@ -13,141 +13,175 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 #ifndef __SESSIONMAP_H__
 #define __SESSIONMAP_H__
 
 #include <utils/KeyedVector.h>
+#include <utils/threads.h>
 
 namespace android {
 
 /**
- * A wrapper template class for handling DRM Engine sessions.
+ * A thread safe wrapper template class for session handlings for Drm Engines. It wraps a
+ * pointer type over KeyedVector. It keeps pointer as data in the vector and free up memory
+ * allocated pointer can be of any type of structure/class meant for keeping session data.
+ * so session object here means pointer to the session data.
  */
-template <typename NODE>
+template <typename TValue>
 class SessionMap {
 
 public:
-    KeyedVector<int, NODE> map;
-
     SessionMap() {}
 
     virtual ~SessionMap() {
+        Mutex::Autolock lock(mLock);
         destroyMap();
     }
 
-/**
- * Adds a new value in the session map table. It expects memory to be allocated already
- * for the session object
- *
- * @param key - key or Session ID
- * @param value - session object to add
- *
- * @return boolean result of adding value. returns false if key is already exist.
- */
-bool addValue(int key, NODE value) {
-    bool result = false;
-
-    if (!isCreated(key)) {
-        map.add(key, value);
-        result = true;
+    /**
+     * Adds a new value in the session map table. It expects memory to be allocated already
+     * for the session object
+     *
+     * @param key - key or Session ID
+     * @param value - session object to add
+     *
+     * @return boolean result of adding value. returns false if key is already exist.
+     */
+    bool addValue(int key, TValue value) {
+        Mutex::Autolock lock(mLock);
+        if (!isCreatedInternal(key)) {
+            map.add(key, value);
+            return true;
+        }
+        return false;
     }
 
-    return result;
-}
-
-
-/**
- * returns the session object by the key
- *
- * @param key - key or Session ID
- *
- * @return session object as per the key
- */
-NODE getValue(int key) {
-    NODE value = NULL;
-
-    if (isCreated(key)) {
-        value = (NODE) map.valueFor(key);
+    /**
+     * returns the session object by the key
+     *
+     * @param key - key or Session ID
+     *
+     * @return session object as per the key
+     */
+    TValue getValue(int key) {
+        Mutex::Autolock lock(mLock);
+        return getValueInternal(key);
     }
 
-    return value;
-}
-
-/**
- * returns the number of objects in the session map table
- *
- * @return count of number of session objects.
- */
-int getSize() {
-    return map.size();
-}
-
-/**
- * returns the session object by the index in the session map table
- *
- * @param index - index of the value required
- *
- * @return session object as per the index
- */
-NODE getValueAt(unsigned int index) {
-    NODE value = NULL;
-
-    if (map.size() > index) {
-      value = map.valueAt(index);
+    /**
+     * returns the number of objects in the session map table
+     *
+     * @return count of number of session objects.
+     */
+    int getSize() {
+        Mutex::Autolock lock(mLock);
+        return map.size();
     }
 
-    return value;
-}
+    /**
+     * returns the session object by the index in the session map table
+     *
+     * @param index - index of the value required
+     *
+     * @return session object as per the index
+     */
+    TValue getValueAt(unsigned int index) {
+        TValue value = NULL;
+        Mutex::Autolock lock(mLock);
 
-/**
- * deletes the object from session map. It also frees up memory for the session object.
- *
- * @param key - key of the value to be deleted
- *
- */
-void removeValue(int key) {
-    deleteValue(getValue(key));
-    map.removeItem(key);
-}
-
-/**
- * decides if session is already created.
- *
- * @param key - key of the value for the session
- *
- * @return boolean result of whether session is created
- */
-bool isCreated(int key) {
-    return (0 <= map.indexOfKey(key));
-}
-
-/**
- * empty the entire session table. It releases all the memory for session objects.
- */
-void destroyMap() {
-    int size = map.size();
-    int i = 0;
-
-    for (i = 0; i < size; i++) {
-        deleteValue(map.valueAt(i));
+        if (map.size() > index) {
+            value = map.valueAt(index);
+        }
+        return value;
     }
 
-    map.clear();
-}
+    /**
+     * deletes the object from session map. It also frees up memory for the session object.
+     *
+     * @param key - key of the value to be deleted
+     *
+     */
+    void removeValue(int key) {
+        Mutex::Autolock lock(mLock);
+        deleteValue(getValueInternal(key));
+        map.removeItem(key);
+    }
 
-/**
- * free up the memory for the session object.
- * Make sure if any reference to the session object anywhere, otherwise it will be a
- * dangle pointer after this call.
- *
- * @param value - session object to free
- *
- */
-void deleteValue(NODE value) {
-    delete value;
-}
+    /**
+     * decides if session is already created.
+     *
+     * @param key - key of the value for the session
+     *
+     * @return boolean result of whether session is created
+     */
+    bool isCreated(int key) {
+        Mutex::Autolock lock(mLock);
+        return isCreatedInternal(key);
+    }
 
+    SessionMap<TValue> & operator=(const SessionMap<TValue> & objectCopy) {
+        Mutex::Autolock lock(mLock);
+
+        destroyMap();
+        map = objectCopy.map;
+        return *this;
+    }
+
+private:
+    KeyedVector<int, TValue> map;
+    Mutex mLock;
+
+   /**
+    * free up the memory for the session object.
+    * Make sure if any reference to the session object anywhere, otherwise it will be a
+    * dangle pointer after this call.
+    *
+    * @param value - session object to free
+    *
+    */
+    void deleteValue(TValue value) {
+        delete value;
+    }
+
+   /**
+    * free up the memory for the entire map.
+    * free up any resources in the sessions before calling this funtion.
+    *
+    */
+    void destroyMap() {
+        int size = map.size();
+
+        for (int i = 0; i < size; i++) {
+            deleteValue(map.valueAt(i));
+        }
+        map.clear();
+    }
+
+   /**
+    * decides if session is already created.
+    *
+    * @param key - key of the value for the session
+    *
+    * @return boolean result of whether session is created
+    */
+    bool isCreatedInternal(int key) {
+        return(0 <= map.indexOfKey(key));
+    }
+
+   /**
+    * returns the session object by the key
+    *
+    * @param key - key or Session ID
+    *
+    * @return session object as per the key
+    */
+    TValue getValueInternal(int key) {
+        TValue value = NULL;
+        if (isCreatedInternal(key)) {
+            value = (TValue) map.valueFor(key);
+        }
+        return value;
+    }
 };
 
 };
diff --git a/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp b/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp
index 4ee903e..57ef799 100644
--- a/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp
+++ b/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp
@@ -22,6 +22,13 @@
 #undef LOG_TAG
 #define LOG_TAG "MimeTypeUtil"
 
+#ifdef DRM_OMA_FL_ENGINE_DEBUG
+#define LOG_NDEBUG 0
+#define LOG_DEBUG(...) LOGD(__VA_ARGS__)
+#else
+#define LOG_DEBUG(...)
+#endif
+
 enum {
     MIMETYPE_AUDIO       = 0,
     MIMETYPE_APPLICATION = 1,
@@ -59,6 +66,7 @@
 static const char mime_group_application[] = "application/";
 static const char mime_group_image[]       = "image/";
 static const char mime_group_video[]       = "video/";
+static const char mime_type_unsupported[]  = "unsupported/drm.mimetype";
 
 static struct MimeGroup mimeGroup[] = {
     {MIMETYPE_AUDIO,       mime_group_audio,        sizeof(mime_group_audio)-1},
@@ -107,48 +115,52 @@
  * replacement mimetype otherwise the original mimetype
  * is returned.
  *
+ * If the mimetype is of unsupported group i.e. application/*
+ * then "unsupported/drm.mimetype" will be returned.
+ *
  * @param mimeType - mimetype in lower case to convert.
  *
- * @return mimetype or null.
+ * @return mimetype or "unsupported/drm.mimetype".
  */
 String8 MimeTypeUtil::convertMimeType(String8& mimeType) {
     String8 result = mimeType;
-    const char* pTmp;
     const char* pMimeType;
     struct MimeGroup* pGroup;
     struct MimeTypeList* pMimeItem;
     int len;
-
     pMimeType = mimeType.string();
     if (NULL != pMimeType) {
-        /* Check which group the mimetype is */
-        pGroup = mimeGroup;
-
-        while (MIMETYPE_LAST != pGroup->type) {
-            if (0 == strncmp(pMimeType, pGroup->pGroup, pGroup->size)) {
-                break;
-            }
-            pGroup++;
-        }
-
-        /* Go through the mimetype list. Only check items of the correct group */
-        if (MIMETYPE_LAST != pGroup->type) {
-            pMimeItem = mimeTypeList;
-            len = strlen (pMimeType+pGroup->size);
-
-            while (MIMETYPE_LAST != pMimeItem->type) {
-                if ((len == pMimeItem->size) &&
-                    (0 == strcmp(pMimeType+pGroup->size, pMimeItem->pMimeExt))) {
-                    result = String8(pMimeItem->pMimeType);
+        if ((0 == strncmp(pMimeType, mime_group_audio, (sizeof mime_group_audio) - 1)) ||
+            (0 == strncmp(pMimeType, mime_group_video, (sizeof mime_group_video) - 1))) {
+            /* Check which group the mimetype is */
+            pGroup = mimeGroup;
+            while (MIMETYPE_LAST != pGroup->type) {
+                if (0 == strncmp(pMimeType, pGroup->pGroup, pGroup->size)) {
                     break;
                 }
-                pMimeItem++;
+                pGroup++;
             }
-        }
-        LOGI("convertMimeType got mimetype %s, converted into mimetype %s",
-             pMimeType, result.string());
-    }
 
+            /* Go through the mimetype list. Only check items of the correct group */
+            if (MIMETYPE_LAST != pGroup->type) {
+                pMimeItem = mimeTypeList;
+                len = strlen (pMimeType+pGroup->size);
+                while (MIMETYPE_LAST != pMimeItem->type) {
+                    if ((pGroup->type == pMimeItem->type) &&
+                        (len == pMimeItem->size) &&
+                        (0 == strcmp(pMimeType+pGroup->size, pMimeItem->pMimeExt))) {
+                        result = String8(pMimeItem->pMimeType);
+                        break;
+                    }
+                    pMimeItem++;
+                }
+            }
+        } else {
+            result = String8(mime_type_unsupported);
+        }
+        LOG_DEBUG("convertMimeType got mimetype %s, converted into mimetype %s",
+                pMimeType, result.string());
+    }
     return result;
 }
 };
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
index 9805a40..e359dbd 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
@@ -17,6 +17,9 @@
 
 include $(CLEAR_VARS)
 
+# The flag below turns on local debug printouts
+#LOCAL_CFLAGS += -DDRM_OMA_FL_ENGINE_DEBUG
+
 base := frameworks/base
 
 # Determine whether the DRM framework uses 64-bit data types for file offsets and do the same.
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
index 31c3c14..e184545 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
@@ -41,6 +41,13 @@
 #undef LOG_TAG
 #define LOG_TAG "FwdLockEngine"
 
+#ifdef DRM_OMA_FL_ENGINE_DEBUG
+#define LOG_NDEBUG 0
+#define LOG_VERBOSE(...) LOGV(__VA_ARGS__)
+#else
+#define LOG_VERBOSE(...)
+#endif
+
 using namespace android;
 // This extern "C" is mandatory to be managed by TPlugInManager
 extern "C" IDrmEngine* create() {
@@ -53,14 +60,25 @@
 }
 
 FwdLockEngine::FwdLockEngine() {
-    LOGV("FwdLockEngine Construction");
+    LOG_VERBOSE("FwdLockEngine Construction");
 }
 
 FwdLockEngine::~FwdLockEngine() {
-    LOGV("FwdLockEngine Destruction");
+    LOG_VERBOSE("FwdLockEngine Destruction");
 
-    convertSessionMap.destroyMap();
-    decodeSessionMap.destroyMap();
+    int size = decodeSessionMap.getSize();
+
+    for (int i = 0; i < size; i++) {
+        DecodeSession *session = (DecodeSession*) decodeSessionMap.getValueAt(i);
+        FwdLockFile_detach(session->fileDesc);
+        ::close(session->fileDesc);
+    }
+
+    size = convertSessionMap.getSize();
+    for (int i = 0; i < size; i++) {
+        ConvertSession *convSession = (ConvertSession*) convertSessionMap.getValueAt(i);
+        FwdLockConv_CloseSession(convSession->uniqueId, &(convSession->output));
+    }
 }
 
 int FwdLockEngine::getConvertedStatus(FwdLockConv_Status_t status) {
@@ -74,12 +92,12 @@
         case FwdLockConv_Status_InvalidArgument:
         case FwdLockConv_Status_UnsupportedFileFormat:
         case FwdLockConv_Status_UnsupportedContentTransferEncoding:
-            LOGD("FwdLockEngine getConvertedStatus: file conversion Error %d. " \
+            LOGE("FwdLockEngine getConvertedStatus: file conversion Error %d. "
                   "Returning STATUS_INPUTDATA_ERROR", status);
             retStatus = DrmConvertedStatus::STATUS_INPUTDATA_ERROR;
             break;
         default:
-            LOGD("FwdLockEngine getConvertedStatus: file conversion Error %d. " \
+            LOGE("FwdLockEngine getConvertedStatus: file conversion Error %d. "
                   "Returning STATUS_ERROR", status);
             retStatus = DrmConvertedStatus::STATUS_ERROR;
             break;
@@ -91,7 +109,7 @@
 DrmConstraints* FwdLockEngine::onGetConstraints(int uniqueId, const String8* path, int action) {
     DrmConstraints* drmConstraints = NULL;
 
-    LOGV("FwdLockEngine::onGetConstraints");
+    LOG_VERBOSE("FwdLockEngine::onGetConstraints");
 
     if (NULL != path &&
         (RightsStatus::RIGHTS_VALID == onCheckRightsStatus(uniqueId, *path, action))) {
@@ -105,7 +123,7 @@
 DrmMetadata* FwdLockEngine::onGetMetadata(int uniqueId, const String8* path) {
     DrmMetadata* drmMetadata = NULL;
 
-    LOGV("FwdLockEngine::onGetMetadata");
+    LOG_VERBOSE("FwdLockEngine::onGetMetadata");
 
     if (NULL != path) {
         // Returns empty metadata to show no error condition.
@@ -116,13 +134,12 @@
 }
 
 android::status_t FwdLockEngine::onInitialize(int uniqueId) {
-    LOGV("FwdLockEngine::onInitialize");
-
+    LOG_VERBOSE("FwdLockEngine::onInitialize");
 
     if (FwdLockGlue_InitializeKeyEncryption()) {
-        LOGV("FwdLockEngine::onInitialize -- FwdLockGlue_InitializeKeyEncryption succeeded");
+        LOG_VERBOSE("FwdLockEngine::onInitialize -- FwdLockGlue_InitializeKeyEncryption succeeded");
     } else {
-        LOGD("FwdLockEngine::onInitialize -- FwdLockGlue_InitializeKeyEncryption failed:"
+        LOGE("FwdLockEngine::onInitialize -- FwdLockGlue_InitializeKeyEncryption failed:"
              "errno = %d", errno);
     }
 
@@ -132,13 +149,13 @@
 android::status_t
 FwdLockEngine::onSetOnInfoListener(int uniqueId, const IDrmEngine::OnInfoListener* infoListener) {
     // Not used
-    LOGV("FwdLockEngine::onSetOnInfoListener");
+    LOG_VERBOSE("FwdLockEngine::onSetOnInfoListener");
 
     return DRM_NO_ERROR;
 }
 
 android::status_t FwdLockEngine::onTerminate(int uniqueId) {
-    LOGV("FwdLockEngine::onTerminate");
+    LOG_VERBOSE("FwdLockEngine::onTerminate");
 
     return DRM_NO_ERROR;
 }
@@ -146,7 +163,7 @@
 DrmSupportInfo* FwdLockEngine::onGetSupportInfo(int uniqueId) {
     DrmSupportInfo* pSupportInfo = new DrmSupportInfo();
 
-    LOGV("FwdLockEngine::onGetSupportInfo");
+    LOG_VERBOSE("FwdLockEngine::onGetSupportInfo");
 
     // fill all Forward Lock mimetypes and extensions
     if (NULL != pSupportInfo) {
@@ -182,7 +199,7 @@
 
     drmInfoStatus = new DrmInfoStatus((int)DrmInfoStatus::STATUS_OK, 0, NULL, String8(""));
 
-    LOGV("FwdLockEngine::onProcessDrmInfo");
+    LOG_VERBOSE("FwdLockEngine::onProcessDrmInfo");
 
     return drmInfoStatus;
 }
@@ -193,7 +210,7 @@
             const String8& rightsPath,
             const String8& contentPath) {
     // No rights to save. Return
-    LOGV("FwdLockEngine::onSaveRights");
+    LOG_VERBOSE("FwdLockEngine::onSaveRights");
     return DRM_ERROR_UNKNOWN;
 }
 
@@ -201,7 +218,7 @@
     DrmInfo* drmInfo = NULL;
 
     // Nothing to be done for Forward Lock file
-    LOGV("FwdLockEngine::onAcquireDrmInfo");
+    LOG_VERBOSE("FwdLockEngine::onAcquireDrmInfo");
 
     return drmInfo;
 }
@@ -211,7 +228,7 @@
                                        int action) {
     int result = RightsStatus::RIGHTS_INVALID;
 
-    LOGV("FwdLockEngine::onCheckRightsStatus");
+    LOG_VERBOSE("FwdLockEngine::onCheckRightsStatus");
 
     // Only Transfer action is not allowed for forward Lock files.
     if (onCanHandle(uniqueId, path)) {
@@ -241,7 +258,7 @@
                                         int action,
                                         bool reserve) {
     // No rights consumption
-    LOGV("FwdLockEngine::onConsumeRights");
+    LOG_VERBOSE("FwdLockEngine::onConsumeRights");
     return DRM_NO_ERROR;
 }
 
@@ -249,14 +266,14 @@
                                      const String8& path,
                                      int action,
                                      const ActionDescription& description) {
-    LOGV("FwdLockEngine::onValidateAction");
+    LOG_VERBOSE("FwdLockEngine::onValidateAction");
 
     // For the forwardlock engine checkRights and ValidateAction are the same.
     return (onCheckRightsStatus(uniqueId, path, action) == RightsStatus::RIGHTS_VALID);
 }
 
 String8 FwdLockEngine::onGetOriginalMimeType(int uniqueId, const String8& path) {
-    LOGV("FwdLockEngine::onGetOriginalMimeType");
+    LOG_VERBOSE("FwdLockEngine::onGetOriginalMimeType");
     String8 mimeString = String8("");
     int fileDesc = FwdLockFile_open(path.string());
 
@@ -280,7 +297,7 @@
                                       const String8& mimeType) {
     String8 mimeStr = String8(mimeType);
 
-    LOGV("FwdLockEngine::onGetDrmObjectType");
+    LOG_VERBOSE("FwdLockEngine::onGetDrmObjectType");
 
     mimeStr.toLower();
 
@@ -301,13 +318,13 @@
 
 status_t FwdLockEngine::onRemoveRights(int uniqueId, const String8& path) {
     // No Rights to remove
-    LOGV("FwdLockEngine::onRemoveRights");
+    LOG_VERBOSE("FwdLockEngine::onRemoveRights");
     return DRM_NO_ERROR;
 }
 
 status_t FwdLockEngine::onRemoveAllRights(int uniqueId) {
     // No rights to remove
-    LOGV("FwdLockEngine::onRemoveAllRights");
+    LOG_VERBOSE("FwdLockEngine::onRemoveAllRights");
     return DRM_NO_ERROR;
 }
 
@@ -319,14 +336,14 @@
                                             int playbackStatus, int position) {
 #endif
     // Not used
-    LOGV("FwdLockEngine::onSetPlaybackStatus");
+    LOG_VERBOSE("FwdLockEngine::onSetPlaybackStatus");
     return DRM_NO_ERROR;
 }
 
 status_t FwdLockEngine::onOpenConvertSession(int uniqueId,
                                          int convertId) {
     status_t result = DRM_ERROR_UNKNOWN;
-    LOGV("FwdLockEngine::onOpenConvertSession");
+    LOG_VERBOSE("FwdLockEngine::onOpenConvertSession");
     if (!convertSessionMap.isCreated(convertId)) {
         ConvertSession *newSession = new ConvertSession();
         if (FwdLockConv_Status_OK ==
@@ -334,7 +351,7 @@
             convertSessionMap.addValue(convertId, newSession);
             result = DRM_NO_ERROR;
         } else {
-            LOGD("FwdLockEngine::onOpenConvertSession -- FwdLockConv_OpenSession failed.");
+            LOGE("FwdLockEngine::onOpenConvertSession -- FwdLockConv_OpenSession failed.");
             delete newSession;
         }
     }
@@ -383,7 +400,7 @@
     DrmBuffer *convResult = new DrmBuffer(NULL, 0);
     int offset = -1;
 
-    LOGV("FwdLockEngine::onCloseConvertSession");
+    LOG_VERBOSE("FwdLockEngine::onCloseConvertSession");
 
     if (convertSessionMap.isCreated(convertId)) {
         ConvertSession *convSession = convertSessionMap.getValue(convertId);
@@ -424,14 +441,14 @@
     status_t result = DRM_ERROR_CANNOT_HANDLE;
     int fileDesc = -1;
 
-    LOGV("FwdLockEngine::onOpenDecryptSession");
+    LOG_VERBOSE("FwdLockEngine::onOpenDecryptSession");
 
     if ((-1 < fd) &&
         (NULL != decryptHandle) &&
         (!decodeSessionMap.isCreated(decryptHandle->decryptId))) {
         fileDesc = dup(fd);
     } else {
-        LOGD("FwdLockEngine::onOpenDecryptSession parameter error");
+        LOGE("FwdLockEngine::onOpenDecryptSession parameter error");
         return result;
     }
 
@@ -453,7 +470,7 @@
             decryptHandle->decryptInfo = NULL;
             result = DRM_NO_ERROR;
         } else {
-            LOGD("FwdLockEngine::onOpenDecryptSession Integrity Check failed for the fd");
+            LOG_VERBOSE("FwdLockEngine::onOpenDecryptSession Integrity Check failed for the fd");
             FwdLockFile_detach(fileDesc);
             delete decodeSession;
         }
@@ -463,7 +480,7 @@
         ::close(fileDesc);
     }
 
-    LOGV("FwdLockEngine::onOpenDecryptSession Exit. result = %d", result);
+    LOG_VERBOSE("FwdLockEngine::onOpenDecryptSession Exit. result = %d", result);
 
     return result;
 }
@@ -500,7 +517,7 @@
 status_t FwdLockEngine::onCloseDecryptSession(int uniqueId,
                                               DecryptHandle* decryptHandle) {
     status_t result = DRM_ERROR_UNKNOWN;
-    LOGV("FwdLockEngine::onCloseDecryptSession");
+    LOG_VERBOSE("FwdLockEngine::onCloseDecryptSession");
 
     if (NULL != decryptHandle && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
         DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
@@ -525,7 +542,7 @@
         decryptHandle = NULL;
     }
 
-    LOGV("FwdLockEngine::onCloseDecryptSession Exit");
+    LOG_VERBOSE("FwdLockEngine::onCloseDecryptSession Exit");
     return result;
 }
 
@@ -533,13 +550,13 @@
                                                 DecryptHandle* decryptHandle,
                                                 int decryptUnitId,
                                                 const DrmBuffer* headerInfo) {
-    LOGV("FwdLockEngine::onInitializeDecryptUnit");
+    LOGE("FwdLockEngine::onInitializeDecryptUnit is not supported for this DRM scheme");
     return DRM_ERROR_UNKNOWN;
 }
 
 status_t FwdLockEngine::onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
             const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
-    LOGV("FwdLockEngine::onDecrypt");
+    LOGE("FwdLockEngine::onDecrypt is not supported for this DRM scheme");
     return DRM_ERROR_UNKNOWN;
 }
 
@@ -548,14 +565,14 @@
                                   int decryptUnitId,
                                   const DrmBuffer* encBuffer,
                                   DrmBuffer** decBuffer) {
-    LOGV("FwdLockEngine::onDecrypt");
+    LOGE("FwdLockEngine::onDecrypt is not supported for this DRM scheme");
     return DRM_ERROR_UNKNOWN;
 }
 
 status_t FwdLockEngine::onFinalizeDecryptUnit(int uniqueId,
                                               DecryptHandle* decryptHandle,
                                               int decryptUnitId) {
-    LOGV("FwdLockEngine::onFinalizeDecryptUnit");
+    LOGE("FwdLockEngine::onFinalizeDecryptUnit is not supported for this DRM scheme");
     return DRM_ERROR_UNKNOWN;
 }
 
@@ -633,11 +650,11 @@
         if (((off_t)-1) != decoderSession->offset) {
             bytesRead = onRead(uniqueId, decryptHandle, buffer, numBytes);
             if (bytesRead < 0) {
-                LOGD("FwdLockEngine::onPread error reading");
+                LOGE("FwdLockEngine::onPread error reading");
             }
         }
     } else {
-        LOGD("FwdLockEngine::onPread decryptId not found");
+        LOGE("FwdLockEngine::onPread decryptId not found");
     }
 
     return bytesRead;
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c
index 14ea9e9..299116d 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c
@@ -275,17 +275,18 @@
 }
 
 /**
- * Checks whether a given character is valid in a boundary. Note that the boundary may contain
- * leading and internal spaces.
+ * Checks whether a given character is valid in a boundary. Allows some non-standard characters that
+ * are invalid according to RFC 2046 but nevertheless used by one vendor's DRM packager. Note that
+ * the boundary may contain leading and internal spaces.
  *
  * @param[in] ch The character to check.
  *
  * @return A Boolean value indicating whether the given character is valid in a boundary.
  */
 static int FwdLockConv_IsBoundaryChar(int ch) {
-    return isalnum(ch) || ch == '\'' ||
-            ch == '(' || ch == ')' || ch == '+' || ch == '_' || ch == ',' || ch == '-' ||
-            ch == '.' || ch == '/' || ch == ':' || ch == '=' || ch == '?' || ch == ' ';
+    return isalnum(ch) || ch == '\'' || ch == '(' || ch == ')' || ch == '+' || ch == '_' ||
+            ch == ',' || ch == '-' || ch == '.' || ch == '/' || ch == ':' || ch == '=' ||
+            ch == '?' || ch == ' ' || ch == '%' || ch == '[' || ch == '&' || ch == '*' || ch == '^';
 }
 
 /**
@@ -1085,6 +1086,13 @@
         status = FwdLockConv_MatchBinaryEncodedData(pSession, ch, pOutput);
         break;
     case FwdLockConv_ParserState_WantsBase64EncodedData:
+        if (ch == '\n' && pSession->scannerState != FwdLockConv_ScannerState_WantsLF) {
+            // Repair base64-encoded data that doesn't have carriage returns in its line breaks.
+            status = FwdLockConv_MatchBase64EncodedData(pSession, '\r', pOutput);
+            if (status != FwdLockConv_Status_OK) {
+                break;
+            }
+        }
         status = FwdLockConv_MatchBase64EncodedData(pSession, ch, pOutput);
         break;
     case FwdLockConv_ParserState_Done:
@@ -1199,7 +1207,7 @@
             status = FwdLockConv_Status_SyntaxError;
         } else {
             // Finalize the data signature.
-            size_t signatureSize;
+            unsigned int signatureSize = SHA1_HASH_SIZE;
             HMAC_Final(&pSession->signingContext, pOutput->fromCloseSession.signatures,
                        &signatureSize);
             if (signatureSize != SHA1_HASH_SIZE) {
@@ -1214,9 +1222,9 @@
                 HMAC_Update(&pSession->signingContext, pSession->pEncryptedSessionKey,
                             pSession->encryptedSessionKeyLength);
                 HMAC_Update(&pSession->signingContext, pOutput->fromCloseSession.signatures,
-                            signatureSize);
-                HMAC_Final(&pSession->signingContext, &pOutput->fromCloseSession.
-                           signatures[signatureSize], &signatureSize);
+                            SHA1_HASH_SIZE);
+                HMAC_Final(&pSession->signingContext,
+                           &pOutput->fromCloseSession.signatures[SHA1_HASH_SIZE], &signatureSize);
                 if (signatureSize != SHA1_HASH_SIZE) {
                     status = FwdLockConv_Status_ProgramError;
                 } else {
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.c b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.c
index 98284e72..dacf00e 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.c
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.c
@@ -114,7 +114,7 @@
 }
 
 /**
- * Finds the file session associated to the given file descriptor.
+ * Finds the file session associated with the given file descriptor.
  *
  * @param[in] fileDesc A file descriptor.
  *
@@ -389,7 +389,7 @@
                 result = FALSE;
             } else {
                 ssize_t numBytesRead;
-                size_t signatureSize = SHA1_HASH_SIZE;
+                unsigned int signatureSize = SHA1_HASH_SIZE;
                 while ((numBytesRead =
                         read(pSession->fileDesc, pData->buffer, SIG_CALC_BUFFER_SIZE)) > 0) {
                     HMAC_Update(&pSession->signingContext, pData->buffer, (size_t)numBytesRead);
@@ -399,7 +399,7 @@
                 } else {
                     HMAC_Final(&pSession->signingContext, pData->signature, &signatureSize);
                     assert(signatureSize == SHA1_HASH_SIZE);
-                    result = memcmp(pData->signature, pSession->dataSignature, signatureSize) == 0;
+                    result = memcmp(pData->signature, pSession->dataSignature, SHA1_HASH_SIZE) == 0;
                 }
                 HMAC_Init_ex(&pSession->signingContext, NULL, KEY_SIZE, NULL, NULL);
                 (void)lseek64(pSession->fileDesc, pSession->dataOffset + pSession->filePos,
@@ -419,16 +419,16 @@
     } else {
         FwdLockFile_Session_t *pSession = sessionPtrs[sessionId];
         unsigned char signature[SHA1_HASH_SIZE];
-        size_t signatureSize = SHA1_HASH_SIZE;
+        unsigned int signatureSize = SHA1_HASH_SIZE;
         HMAC_Update(&pSession->signingContext, pSession->topHeader, TOP_HEADER_SIZE);
         HMAC_Update(&pSession->signingContext, (unsigned char *)pSession->pContentType,
                     pSession->contentTypeLength);
         HMAC_Update(&pSession->signingContext, pSession->pEncryptedSessionKey,
                     pSession->encryptedSessionKeyLength);
-        HMAC_Update(&pSession->signingContext, pSession->dataSignature, signatureSize);
+        HMAC_Update(&pSession->signingContext, pSession->dataSignature, SHA1_HASH_SIZE);
         HMAC_Final(&pSession->signingContext, signature, &signatureSize);
         assert(signatureSize == SHA1_HASH_SIZE);
-        result = memcmp(signature, pSession->headerSignature, signatureSize) == 0;
+        result = memcmp(signature, pSession->headerSignature, SHA1_HASH_SIZE) == 0;
         HMAC_Init_ex(&pSession->signingContext, NULL, KEY_SIZE, NULL, NULL);
     }
     return result;
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 40d54bb..3fc6463 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -567,6 +567,7 @@
         
         canvas.setBitmap(bitmap);
         canvas.drawBitmap(source, srcR, dstR, paint);
+        canvas.setBitmap(null);
 
         return bitmap;
     }
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index b8e9384..7269a71 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -84,9 +84,19 @@
     public static final int JPEG = 0x100;
 
     /**
+     * Raw bayer format used for images, which is 10 bit precision samples
+     * stored in 16 bit words. The filter pattern is RGGB. Whether this format
+     * is supported by the camera hardware can be determined by
+     * {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}.
+     *
+     * @hide
+     */
+    public static final int BAYER_RGGB = 0x200;
+
+    /**
      * Use this function to retrieve the number of bits per pixel of an
      * ImageFormat.
-     * 
+     *
      * @param format
      * @return the number of bits per pixel of the given format or -1 if the
      *         format doesn't exist or is not supported.
@@ -103,6 +113,8 @@
                 return 12;
             case NV21:
                 return 12;
+            case BAYER_RGGB:
+                return 16;
         }
         return -1;
     }
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index 1647ff3..d62fd67 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -187,6 +187,25 @@
         return nativeGetTimestamp();
     }
 
+    /**
+     * release() frees all the buffers and puts the SurfaceTexture into the
+     * 'abandoned' state. Once put in this state the SurfaceTexture can never
+     * leave it. When in the 'abandoned' state, all methods of the
+     * ISurfaceTexture interface will fail with the NO_INIT error.
+     *
+     * Note that while calling this method causes all the buffers to be freed
+     * from the perspective of the the SurfaceTexture, if there are additional
+     * references on the buffers (e.g. if a buffer is referenced by a client or
+     * by OpenGL ES as a texture) then those buffer will remain allocated.
+     *
+     * Always call this method when you are done with SurfaceTexture. Failing
+     * to do so may delay resource deallocation for a significant amount of
+     * time.
+     */
+    public void release() {
+        nativeRelease();
+    }
+
     protected void finalize() throws Throwable {
         try {
             nativeFinalize();
@@ -232,6 +251,7 @@
     private native void nativeSetDefaultBufferSize(int width, int height);
     private native void nativeUpdateTexImage();
     private native int nativeGetQueuedCount();
+    private native void nativeRelease();
 
     /*
      * We use a class initializer to allow the native code to cache some
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 4856ab6..571b895 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -19,6 +19,8 @@
 import java.lang.reflect.Field;
 
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -28,6 +30,7 @@
 import android.view.Surface;
 
 
+
 /**
  * RenderScript base master class.  An instance of this class creates native
  * worker threads for processing commands from this object.  This base class
@@ -79,26 +82,26 @@
 
     // Methods below are wrapped to protect the non-threadsafe
     // lockless fifo.
-    native int  rsnContextCreateGL(int dev, int ver,
+    native int  rsnContextCreateGL(int dev, int ver, int sdkVer,
                  int colorMin, int colorPref,
                  int alphaMin, int alphaPref,
                  int depthMin, int depthPref,
                  int stencilMin, int stencilPref,
                  int samplesMin, int samplesPref, float samplesQ, int dpi);
-    synchronized int nContextCreateGL(int dev, int ver,
+    synchronized int nContextCreateGL(int dev, int ver, int sdkVer,
                  int colorMin, int colorPref,
                  int alphaMin, int alphaPref,
                  int depthMin, int depthPref,
                  int stencilMin, int stencilPref,
                  int samplesMin, int samplesPref, float samplesQ, int dpi) {
-        return rsnContextCreateGL(dev, ver, colorMin, colorPref,
+        return rsnContextCreateGL(dev, ver, sdkVer, colorMin, colorPref,
                                   alphaMin, alphaPref, depthMin, depthPref,
                                   stencilMin, stencilPref,
                                   samplesMin, samplesPref, samplesQ, dpi);
     }
-    native int  rsnContextCreate(int dev, int ver);
-    synchronized int nContextCreate(int dev, int ver) {
-        return rsnContextCreate(dev, ver);
+    native int  rsnContextCreate(int dev, int ver, int sdkVer);
+    synchronized int nContextCreate(int dev, int ver, int sdkVer) {
+        return rsnContextCreate(dev, ver, sdkVer);
     }
     native void rsnContextDestroy(int con);
     synchronized void nContextDestroy() {
@@ -864,6 +867,16 @@
         return mApplicationContext;
     }
 
+    static int getTargetSdkVersion(Context ctx) {
+        try {
+            PackageManager pm = ctx.getPackageManager();
+            ApplicationInfo app = pm.getApplicationInfo(ctx.getPackageName(), 0);
+            return app.targetSdkVersion;
+        } catch (Exception e) {
+            throw new RSDriverException("Error calculating target SDK version for RS.");
+        }
+    }
+
     /**
      * Create a basic RenderScript context.
      *
@@ -873,8 +886,10 @@
     public static RenderScript create(Context ctx) {
         RenderScript rs = new RenderScript(ctx);
 
+        int sdkVersion = getTargetSdkVersion(ctx);
+
         rs.mDev = rs.nDeviceCreate();
-        rs.mContext = rs.nContextCreate(rs.mDev, 0);
+        rs.mContext = rs.nContextCreate(rs.mDev, 0, sdkVersion);
         if (rs.mContext == 0) {
             throw new RSDriverException("Failed to create RS context.");
         }
diff --git a/graphics/java/android/renderscript/RenderScriptGL.java b/graphics/java/android/renderscript/RenderScriptGL.java
index 935b75a..2dfcc83 100644
--- a/graphics/java/android/renderscript/RenderScriptGL.java
+++ b/graphics/java/android/renderscript/RenderScriptGL.java
@@ -160,11 +160,13 @@
         super(ctx);
         mSurfaceConfig = new SurfaceConfig(sc);
 
+        int sdkVersion = getTargetSdkVersion(ctx);
+
         mWidth = 0;
         mHeight = 0;
         mDev = nDeviceCreate();
         int dpi = ctx.getResources().getDisplayMetrics().densityDpi;
-        mContext = nContextCreateGL(mDev, 0,
+        mContext = nContextCreateGL(mDev, 0, sdkVersion,
                                     mSurfaceConfig.mColorMin, mSurfaceConfig.mColorPref,
                                     mSurfaceConfig.mAlphaMin, mSurfaceConfig.mAlphaPref,
                                     mSurfaceConfig.mDepthMin, mSurfaceConfig.mDepthPref,
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 3476bd5..d7ac5d8 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -149,14 +149,14 @@
 }
 
 static jint
-nContextCreate(JNIEnv *_env, jobject _this, jint dev, jint ver)
+nContextCreate(JNIEnv *_env, jobject _this, jint dev, jint ver, jint sdkVer)
 {
     LOG_API("nContextCreate");
-    return (jint)rsContextCreate((RsDevice)dev, ver);
+    return (jint)rsContextCreate((RsDevice)dev, ver, sdkVer);
 }
 
 static jint
-nContextCreateGL(JNIEnv *_env, jobject _this, jint dev, jint ver,
+nContextCreateGL(JNIEnv *_env, jobject _this, jint dev, jint ver, jint sdkVer,
                  int colorMin, int colorPref,
                  int alphaMin, int alphaPref,
                  int depthMin, int depthPref,
@@ -176,7 +176,7 @@
     sc.samplesQ = samplesQ;
 
     LOG_API("nContextCreateGL");
-    return (jint)rsContextCreateGL((RsDevice)dev, ver, sc, dpi);
+    return (jint)rsContextCreateGL((RsDevice)dev, ver, sdkVer, sc, dpi);
 }
 
 static void
@@ -1213,8 +1213,8 @@
 
 
 // All methods below are thread protected in java.
-{"rsnContextCreate",                 "(II)I",                                 (void*)nContextCreate },
-{"rsnContextCreateGL",               "(IIIIIIIIIIIIFI)I",                     (void*)nContextCreateGL },
+{"rsnContextCreate",                 "(III)I",                                (void*)nContextCreate },
+{"rsnContextCreateGL",               "(IIIIIIIIIIIIIFI)I",                    (void*)nContextCreateGL },
 {"rsnContextFinish",                 "(I)V",                                  (void*)nContextFinish },
 {"rsnContextSetPriority",            "(II)V",                                 (void*)nContextSetPriority },
 {"rsnContextSetSurface",             "(IIILandroid/view/Surface;)V",          (void*)nContextSetSurface },
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 48483fd..b661496 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -573,6 +573,9 @@
     static const char PIXEL_FORMAT_RGB565[];
     static const char PIXEL_FORMAT_RGBA8888[];
     static const char PIXEL_FORMAT_JPEG[];
+    // Raw bayer format used for images, which is 10 bit precision samples
+    // stored in 16 bit words. The filter pattern is RGGB.
+    static const char PIXEL_FORMAT_BAYER_RGGB[];
 
     // Values for focus mode settings.
     // Auto-focus mode. Applications should call
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
index c1c4f94..3d79596 100644
--- a/include/media/stagefright/MediaBuffer.h
+++ b/include/media/stagefright/MediaBuffer.h
@@ -25,6 +25,7 @@
 
 namespace android {
 
+struct ABuffer;
 class GraphicBuffer;
 class MediaBuffer;
 class MediaBufferObserver;
@@ -51,6 +52,8 @@
 
     MediaBuffer(const sp<GraphicBuffer>& graphicBuffer);
 
+    MediaBuffer(const sp<ABuffer> &buffer);
+
     // Decrements the reference count and returns the buffer to its
     // associated MediaBufferGroup if the reference count drops to 0.
     void release();
@@ -100,6 +103,7 @@
     void *mData;
     size_t mSize, mRangeOffset, mRangeLength;
     sp<GraphicBuffer> mGraphicBuffer;
+    sp<ABuffer> mBuffer;
 
     bool mOwnsData;
 
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index 251615d..51b96c1 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -151,6 +151,7 @@
 const char CameraParameters::PIXEL_FORMAT_RGB565[] = "rgb565";
 const char CameraParameters::PIXEL_FORMAT_RGBA8888[] = "rgba8888";
 const char CameraParameters::PIXEL_FORMAT_JPEG[] = "jpeg";
+const char CameraParameters::PIXEL_FORMAT_BAYER_RGGB[] = "bayer-rggb";
 
 // Values for focus mode settings.
 const char CameraParameters::FOCUS_MODE_AUTO[] = "auto";
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 4f51f03..1a036ee 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -910,6 +910,7 @@
     Mutex::Autolock lock(mMutex);
     freeAllBuffers();
     mAbandoned = true;
+    mCurrentTextureBuf.clear();
     mDequeueCondition.signal();
 }
 
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 9bf3de8..9acf99b 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -44,9 +44,11 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 Font::Font(FontRenderer* state, uint32_t fontId, float fontSize,
-        int flags, uint32_t italicStyle, uint32_t scaleX) :
+        int flags, uint32_t italicStyle, uint32_t scaleX,
+        SkPaint::Style style, uint32_t strokeWidth) :
         mState(state), mFontId(fontId), mFontSize(fontSize),
-        mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX) {
+        mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX),
+        mStyle(style), mStrokeWidth(mStrokeWidth) {
 }
 
 
@@ -283,19 +285,22 @@
 }
 
 Font* Font::create(FontRenderer* state, uint32_t fontId, float fontSize,
-        int flags, uint32_t italicStyle, uint32_t scaleX) {
+        int flags, uint32_t italicStyle, uint32_t scaleX,
+        SkPaint::Style style, uint32_t strokeWidth) {
     Vector<Font*> &activeFonts = state->mActiveFonts;
 
     for (uint32_t i = 0; i < activeFonts.size(); i++) {
         Font* font = activeFonts[i];
         if (font->mFontId == fontId && font->mFontSize == fontSize &&
                 font->mFlags == flags && font->mItalicStyle == italicStyle &&
-                font->mScaleX == scaleX) {
+                font->mScaleX == scaleX && font->mStyle == style &&
+                (style == SkPaint::kFill_Style || font->mStrokeWidth == strokeWidth)) {
             return font;
         }
     }
 
-    Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle, scaleX);
+    Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle,
+            scaleX, style, strokeWidth);
     activeFonts.push(newFont);
     return newFont;
 }
@@ -690,7 +695,11 @@
     uint32_t italicStyle = *(uint32_t*) &skewX;
     const float scaleXFloat = paint->getTextScaleX();
     uint32_t scaleX = *(uint32_t*) &scaleXFloat;
-    mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle, scaleX);
+    SkPaint::Style style = paint->getStyle();
+    const float strokeWidthFloat = paint->getStrokeWidth();
+    uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat;
+    mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle,
+            scaleX, style, strokeWidth);
 
     const float maxPrecacheFontSize = 40.0f;
     bool isNewFont = currentNumFonts != mActiveFonts.size();
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 24ed6fa..1922812 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -82,7 +82,8 @@
      * Creates a new font associated with the specified font state.
      */
     static Font* create(FontRenderer* state, uint32_t fontId, float fontSize,
-            int flags, uint32_t italicStyle, uint32_t scaleX);
+            int flags, uint32_t italicStyle, uint32_t scaleX, SkPaint::Style style,
+            uint32_t strokeWidth);
 
 protected:
     friend class FontRenderer;
@@ -128,7 +129,7 @@
     };
 
     Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags, uint32_t italicStyle,
-            uint32_t scaleX);
+            uint32_t scaleX, SkPaint::Style style, uint32_t strokeWidth);
 
     // Cache of glyphs
     DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs;
@@ -157,6 +158,8 @@
     int mFlags;
     uint32_t mItalicStyle;
     uint32_t mScaleX;
+    SkPaint::Style mStyle;
+    uint32_t mStrokeWidth;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index 535f713..3ba0123 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -52,8 +52,8 @@
 RsDevice rsDeviceCreate();
 void rsDeviceDestroy(RsDevice dev);
 void rsDeviceSetConfig(RsDevice dev, RsDeviceParam p, int32_t value);
-RsContext rsContextCreate(RsDevice dev, uint32_t version);
-RsContext rsContextCreateGL(RsDevice dev, uint32_t version, RsSurfaceConfig sc, uint32_t dpi);
+RsContext rsContextCreate(RsDevice dev, uint32_t version, uint32_t sdkVersion);
+RsContext rsContextCreateGL(RsDevice dev, uint32_t version, uint32_t sdkVersion, RsSurfaceConfig sc, uint32_t dpi);
 
 #include "rsgApiFuncDecl.h"
 
diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp
index 86bec6e..fb2df37 100644
--- a/libs/rs/driver/rsdBcc.cpp
+++ b/libs/rs/driver/rsdBcc.cpp
@@ -19,7 +19,7 @@
 #include "rsdBcc.h"
 #include "rsdRuntime.h"
 
-#include <bcinfo/bcinfo.h>
+#include <bcinfo/MetadataExtractor.h>
 
 #include "rsContext.h"
 #include "rsScriptC.h"
@@ -40,7 +40,7 @@
 
     BCCScriptRef mBccScript;
 
-    struct BCScriptMetadata *mScriptMetadata;
+    bcinfo::MetadataExtractor *ME;
 
     InvokeFunc_t *mInvokeFunctions;
     void ** mFieldAddress;
@@ -71,7 +71,9 @@
 
     pthread_mutex_lock(&rsdgInitMutex);
     char *cachePath = NULL;
-    struct BCScriptMetadata *md = NULL;
+    size_t exportFuncCount = 0;
+    size_t exportVarCount = 0;
+    size_t objectSlotCount = 0;
 
     DrvScript *drv = (DrvScript *)calloc(1, sizeof(DrvScript));
     if (drv == NULL) {
@@ -84,13 +86,13 @@
     drv->mScriptText = bitcode;
     drv->mScriptTextLength = bitcodeSize;
 
-    md = bcinfoGetScriptMetadata((const char*)drv->mScriptText,
-                                 drv->mScriptTextLength, 0);
-    if (!md) {
+
+    drv->ME = new bcinfo::MetadataExtractor((const char*)drv->mScriptText,
+                                            drv->mScriptTextLength);
+    if (!drv->ME->extract()) {
       LOGE("bcinfo: failed to read script metadata");
       goto error;
     }
-    drv->mScriptMetadata = md;
 
     //LOGE("mBccScript %p", script->mBccScript);
 
@@ -122,40 +124,41 @@
     drv->mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(drv->mBccScript, "root"));
     drv->mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(drv->mBccScript, "init"));
 
-    if (md->exportFuncCount > 0) {
-        drv->mInvokeFunctions = (InvokeFunc_t*) calloc(md->exportFuncCount,
+    exportFuncCount = drv->ME->getExportFuncCount();
+    if (exportFuncCount > 0) {
+        drv->mInvokeFunctions = (InvokeFunc_t*) calloc(exportFuncCount,
                                                        sizeof(InvokeFunc_t));
-        bccGetExportFuncList(drv->mBccScript,
-                             md->exportFuncCount,
+        bccGetExportFuncList(drv->mBccScript, exportFuncCount,
                              (void **) drv->mInvokeFunctions);
     } else {
         drv->mInvokeFunctions = NULL;
     }
 
-    if (md->exportVarCount > 0) {
-        drv->mFieldAddress = (void **) calloc(md->exportVarCount,
-                                              sizeof(void*));
-        drv->mFieldIsObject = (bool *) calloc(md->exportVarCount, sizeof(bool));
-        bccGetExportVarList(drv->mBccScript,
-                            md->exportVarCount,
+    exportVarCount = drv->ME->getExportVarCount();
+    if (exportVarCount > 0) {
+        drv->mFieldAddress = (void **) calloc(exportVarCount, sizeof(void*));
+        drv->mFieldIsObject = (bool *) calloc(exportVarCount, sizeof(bool));
+        bccGetExportVarList(drv->mBccScript, exportVarCount,
                             (void **) drv->mFieldAddress);
     } else {
         drv->mFieldAddress = NULL;
         drv->mFieldIsObject = NULL;
     }
 
-    if (md->objectSlotCount) {
-        for (uint32_t ct=0; ct < md->objectSlotCount; ct++) {
-            drv->mFieldIsObject[md->objectSlotList[ct]] = true;
+    objectSlotCount = drv->ME->getObjectSlotCount();
+    if (objectSlotCount > 0) {
+        const uint32_t *objectSlotList = drv->ME->getObjectSlotList();
+        for (uint32_t ct=0; ct < objectSlotCount; ct++) {
+            drv->mFieldIsObject[objectSlotList[ct]] = true;
         }
     }
 
     // Copy info over to runtime
-    script->mHal.info.exportedFunctionCount = md->exportFuncCount;
-    script->mHal.info.exportedVariableCount = md->exportVarCount;
-    script->mHal.info.exportedPragmaCount = md->pragmaCount;
-    script->mHal.info.exportedPragmaKeyList = md->pragmaKeyList;
-    script->mHal.info.exportedPragmaValueList = md->pragmaValueList;
+    script->mHal.info.exportedFunctionCount = drv->ME->getExportFuncCount();
+    script->mHal.info.exportedVariableCount = drv->ME->getExportVarCount();
+    script->mHal.info.exportedPragmaCount = drv->ME->getPragmaCount();
+    script->mHal.info.exportedPragmaKeyList = drv->ME->getPragmaKeyList();
+    script->mHal.info.exportedPragmaValueList = drv->ME->getPragmaValueList();
     script->mHal.info.root = drv->mRoot;
 
     pthread_mutex_unlock(&rsdgInitMutex);
@@ -164,6 +167,10 @@
 error:
 
     pthread_mutex_unlock(&rsdgInitMutex);
+    if (drv->ME) {
+        delete drv->ME;
+        drv->ME = NULL;
+    }
     free(drv);
     return false;
 
@@ -445,10 +452,10 @@
 
 void rsdScriptDestroy(const Context *dc, Script *script) {
     DrvScript *drv = (DrvScript *)script->mHal.drv;
-    struct BCScriptMetadata *md = drv->mScriptMetadata;
 
     if (drv->mFieldAddress) {
-        for (size_t ct = 0; ct < md->exportVarCount; ct++) {
+        size_t exportVarCount = drv->ME->getExportVarCount();
+        for (size_t ct = 0; ct < exportVarCount; ct++) {
             if (drv->mFieldIsObject[ct]) {
                 // The field address can be NULL if the script-side has
                 // optimized the corresponding global variable away.
@@ -467,7 +474,8 @@
         drv->mInvokeFunctions = NULL;
     }
 
-    bcinfoReleaseScriptMetadata(&drv->mScriptMetadata);
+    delete drv->ME;
+    drv->ME = NULL;
 
     free(drv);
     script->mHal.drv = NULL;
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index decd9f1..6a30b17 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -333,6 +333,7 @@
     mPaused = false;
     mObjHead = NULL;
     mError = RS_ERROR_NONE;
+    mTargetSdkVersion = 14;
     mDPI = 96;
     mIsContextLite = false;
 }
@@ -678,19 +679,25 @@
 }
 }
 
-RsContext rsContextCreate(RsDevice vdev, uint32_t version) {
+RsContext rsContextCreate(RsDevice vdev, uint32_t version,
+                          uint32_t sdkVersion) {
     LOGV("rsContextCreate %p", vdev);
     Device * dev = static_cast<Device *>(vdev);
     Context *rsc = Context::createContext(dev, NULL);
+    if (rsc) {
+        rsc->setTargetSdkVersion(sdkVersion);
+    }
     return rsc;
 }
 
 RsContext rsContextCreateGL(RsDevice vdev, uint32_t version,
-                            RsSurfaceConfig sc, uint32_t dpi) {
+                            uint32_t sdkVersion, RsSurfaceConfig sc,
+                            uint32_t dpi) {
     LOGV("rsContextCreateGL %p", vdev);
     Device * dev = static_cast<Device *>(vdev);
     Context *rsc = Context::createContext(dev, &sc);
     if (rsc) {
+        rsc->setTargetSdkVersion(sdkVersion);
         rsc->setDPI(dpi);
     }
     LOGV("rsContextCreateGL ret %p ", rsc);
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 309fe95..3c7a3d2 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -199,9 +199,13 @@
     uint32_t getDPI() const {return mDPI;}
     void setDPI(uint32_t dpi) {mDPI = dpi;}
 
+    uint32_t getTargetSdkVersion() const {return mTargetSdkVersion;}
+    void setTargetSdkVersion(uint32_t sdkVer) {mTargetSdkVersion = sdkVer;}
+
     Device *mDev;
 protected:
 
+    uint32_t mTargetSdkVersion;
     uint32_t mDPI;
     uint32_t mWidth;
     uint32_t mHeight;
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index e8b1014..dccf71f 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -19,6 +19,10 @@
 #include "utils/Timers.h"
 #include "utils/StopWatch.h"
 
+#ifndef ANDROID_RS_SERIALIZE
+#include <bcinfo/BitcodeTranslator.h>
+#endif
+
 using namespace android;
 using namespace android::renderscript;
 
@@ -28,9 +32,18 @@
     ScriptC * sc = (ScriptC *) tls->mScript
 
 ScriptC::ScriptC(Context *rsc) : Script(rsc) {
+#ifndef ANDROID_RS_SERIALIZE
+    BT = NULL;
+#endif
 }
 
 ScriptC::~ScriptC() {
+#ifndef ANDROID_RS_SERIALIZE
+    if (BT) {
+        delete BT;
+        BT = NULL;
+    }
+#endif
     mRSC->mHal.funcs.script.destroy(mRSC, this);
 }
 
@@ -181,6 +194,22 @@
                           size_t bitcodeLen) {
 
     //LOGE("runCompiler %p %p %p %p %p %i", rsc, this, resName, cacheDir, bitcode, bitcodeLen);
+#ifndef ANDROID_RS_SERIALIZE
+    uint32_t sdkVersion = rsc->getTargetSdkVersion();
+    if (BT) {
+        delete BT;
+    }
+    BT = new bcinfo::BitcodeTranslator((const char *)bitcode, bitcodeLen,
+                                       sdkVersion);
+    if (!BT->translate()) {
+        LOGE("Failed to translate bitcode from version: %u", sdkVersion);
+        delete BT;
+        BT = NULL;
+        return false;
+    }
+    bitcode = (const uint8_t *) BT->getTranslatedBitcode();
+    bitcodeLen = BT->getTranslatedBitcodeSize();
+#endif
 
     rsc->mHal.funcs.script.init(rsc, this, resName, cacheDir, bitcode, bitcodeLen, 0);
 
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index 5c191d9..c65a5bf 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -21,6 +21,9 @@
 
 #include "RenderScriptEnv.h"
 
+#ifndef ANDROID_RS_SERIALIZE
+#include "bcinfo/BitcodeTranslator.h"
+#endif
 
 // ---------------------------------------------------------------------------
 namespace android {
@@ -61,6 +64,10 @@
     void setupScript(Context *);
     void setupGLState(Context *);
     Script * setTLS(Script *);
+  private:
+#ifndef ANDROID_RS_SERIALIZE
+    bcinfo::BitcodeTranslator *BT;
+#endif
 };
 
 class ScriptCState {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 7258e11..e613523 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1646,7 +1646,8 @@
         IAudioService service = getService();
         try {
             status = service.requestAudioFocus(streamType, durationHint, mICallBack,
-                    mAudioFocusDispatcher, getIdForAudioFocusListener(l));
+                    mAudioFocusDispatcher, getIdForAudioFocusListener(l),
+                    mContext.getPackageName() /* package name */);
         } catch (RemoteException e) {
             Log.e(TAG, "Can't call requestAudioFocus() from AudioService due to "+e);
         }
@@ -1682,7 +1683,9 @@
      *      in the application manifest.
      */
     public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
-        //TODO enforce the rule about the receiver being declared in the manifest
+        if (eventReceiver == null) {
+            return;
+        }
         IAudioService service = getService();
         try {
             service.registerMediaButtonEventReceiver(eventReceiver);
@@ -1697,6 +1700,9 @@
      *      that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
      */
     public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
+        if (eventReceiver == null) {
+            return;
+        }
         IAudioService service = getService();
         try {
             service.unregisterMediaButtonEventReceiver(eventReceiver);
@@ -1706,6 +1712,168 @@
     }
 
     /**
+     * @hide
+     * Registers the remote control client for providing information to display on the remotes.
+     * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
+     *      that will receive the media button intent, and associated with the remote control
+     *      client. This method has no effect if
+     *      {@link #registerMediaButtonEventReceiver(ComponentName)} hasn't been called
+     *      with the same eventReceiver, or if
+     *      {@link #unregisterMediaButtonEventReceiver(ComponentName)} has been called.
+     * @param rcClient the client associated with the event receiver, responsible for providing
+     *      the information to display on the remote control.
+     */
+    public void registerRemoteControlClient(ComponentName eventReceiver,
+            IRemoteControlClient rcClient) {
+        if (eventReceiver == null) {
+            return;
+        }
+        IAudioService service = getService();
+        try {
+            service.registerRemoteControlClient(eventReceiver, rcClient,
+                    // used to match media button event receiver and audio focus
+                    mContext.getPackageName());
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in registerRemoteControlClient"+e);
+        }
+    }
+
+    /**
+     * @hide
+     * @param eventReceiver
+     */
+    public void unregisterRemoteControlClient(ComponentName eventReceiver) {
+        if (eventReceiver == null) {
+            return;
+        }
+        IAudioService service = getService();
+        try {
+            // unregistering a IRemoteControlClient is equivalent to setting it to null
+            service.registerRemoteControlClient(eventReceiver, null, mContext.getPackageName());
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in unregisterRemoteControlClient"+e);
+        }
+    }
+
+    /**
+     * @hide
+     * Returns the current remote control client.
+     * @param rcClientId the counter value that matches the extra
+     *     {@link AudioManager#EXTRA_REMOTE_CONTROL_CLIENT} in the
+     *     {@link AudioManager#REMOTE_CONTROL_CLIENT_CHANGED} event
+     * @return the current IRemoteControlClient from which information to display on the remote
+     *     control can be retrieved, or null if rcClientId doesn't match the current generation
+     *     counter.
+     */
+    public IRemoteControlClient getRemoteControlClient(int rcClientId) {
+        IAudioService service = getService();
+        try {
+            return service.getRemoteControlClient(rcClientId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in getRemoteControlClient "+e);
+            return null;
+        }
+    }
+
+    /**
+     * @hide
+     * Returns the current remote control client flags describing what information has changed.
+     * The flags are reset everytime this method is called with a valid rcClientId.
+     * @param rcClientId the counter value that matches the extra
+     *     {@link AudioManager#EXTRA_REMOTE_CONTROL_CLIENT} in the
+     *     {@link AudioManager#REMOTE_CONTROL_CLIENT_CHANGED} event
+     * @return the "information changed" flags from the current IRemoteControlClient from
+     *     which information to display on the remote control can be retrieved,
+     *     or 0 if rcClientId doesn't match the current generation counter.
+     */
+    public int getRemoteControlClientInformationChangedFlags(int rcClientId) {
+        IAudioService service = getService();
+        try {
+            return service.getRemoteControlClientInformationChangedFlags(rcClientId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in getRemoteControlClientInformationChangedFlags "+e);
+            return 0;
+        }
+    }
+
+    /**
+     * @hide
+     * Definitions of constants to be used in {@link android.media.IRemoteControlClient}.
+     */
+    public final class RemoteControlParameters {
+        public final static int PLAYSTATE_STOPPED            = 1;
+        public final static int PLAYSTATE_PAUSED             = 2;
+        public final static int PLAYSTATE_PLAYING            = 3;
+        public final static int PLAYSTATE_FAST_FORWARDING    = 4;
+        public final static int PLAYSTATE_REWINDING          = 5;
+        public final static int PLAYSTATE_SKIPPING_FORWARDS  = 6;
+        public final static int PLAYSTATE_SKIPPING_BACKWARDS = 7;
+        public final static int PLAYSTATE_BUFFERING          = 8;
+
+        public final static int FLAG_KEY_MEDIA_PREVIOUS = 1 << 0;
+        public final static int FLAG_KEY_MEDIA_REWIND = 1 << 1;
+        public final static int FLAG_KEY_MEDIA_PLAY = 1 << 2;
+        public final static int FLAG_KEY_MEDIA_PLAY_PAUSE = 1 << 3;
+        public final static int FLAG_KEY_MEDIA_PAUSE = 1 << 4;
+        public final static int FLAG_KEY_MEDIA_STOP = 1 << 5;
+        public final static int FLAG_KEY_MEDIA_FAST_FORWARD = 1 << 6;
+        public final static int FLAG_KEY_MEDIA_NEXT = 1 << 7;
+
+        public final static int FLAG_INFORMATION_CHANGED_METADATA = 1 << 0;
+        public final static int FLAG_INFORMATION_CHANGED_KEY_MEDIA = 1 << 1;
+        public final static int FLAG_INFORMATION_CHANGED_PLAYSTATE = 1 << 2;
+        public final static int FLAG_INFORMATION_CHANGED_ALBUM_ART = 1 << 3;
+    }
+
+    /**
+     * @hide
+     * Broadcast intent action indicating that the displays on the remote controls
+     * should be updated because a new remote control client is now active. If there is no
+     * {@link #EXTRA_REMOTE_CONTROL_CLIENT}, the remote control display should be cleared
+     * because there is no valid client to supply it with information.
+     *
+     * @see #EXTRA_REMOTE_CONTROL_CLIENT
+     */
+    public static final String REMOTE_CONTROL_CLIENT_CHANGED =
+            "android.media.REMOTE_CONTROL_CLIENT_CHANGED";
+
+    /**
+     * @hide
+     * The IRemoteControlClient monotonically increasing generation counter.
+     *
+     * @see #REMOTE_CONTROL_CLIENT_CHANGED_ACTION
+     */
+    public static final String EXTRA_REMOTE_CONTROL_CLIENT =
+            "android.media.EXTRA_REMOTE_CONTROL_CLIENT";
+
+    /**
+     * @hide
+     * Notifies the users of the associated remote control client that the information to display
+     * has changed.
+     @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
+     *      that will receive the media button intent, and associated with the remote control
+     *      client. This method has no effect if
+     *      {@link #registerMediaButtonEventReceiver(ComponentName)} hasn't been called
+     *      with the same eventReceiver, or if
+     *      {@link #unregisterMediaButtonEventReceiver(ComponentName)} has been called.
+     * @param infoFlag the type of information that has changed since this method was last called,
+     *      or the event receiver was registered. Use one or multiple of the following flags to
+     *      describe what changed:
+     *      {@link RemoteControlParameters#FLAG_INFORMATION_CHANGED_METADATA},
+     *      {@link RemoteControlParameters#FLAG_INFORMATION_CHANGED_KEY_MEDIA},
+     *      {@link RemoteControlParameters#FLAG_INFORMATION_CHANGED_PLAYSTATE},
+     *      {@link RemoteControlParameters#FLAG_INFORMATION_CHANGED_ALBUM_ART}.
+     */
+    public void notifyRemoteControlInformationChanged(ComponentName eventReceiver, int infoFlag) {
+        IAudioService service = getService();
+        try {
+            service.notifyRemoteControlInformationChanged(eventReceiver, infoFlag);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in refreshRemoteControlDisplay"+e);
+        }
+    }
+
+    /**
      *  @hide
      *  Reload audio settings. This method is called by Settings backup
      *  agent when audio settings are restored and causes the AudioService
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 682560a..c628be1 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -55,6 +55,7 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.lang.ref.SoftReference;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -113,6 +114,8 @@
     private static final int MSG_SET_FORCE_USE = 10;
     private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 11;
     private static final int MSG_BT_HEADSET_CNCT_FAILED = 12;
+    private static final int MSG_RCDISPLAY_CLEAR = 13;
+    private static final int MSG_RCDISPLAY_UPDATE = 14;
 
     private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
     // Timeout for connection to bluetooth headset service
@@ -184,7 +187,7 @@
         AudioSystem.STREAM_RING,  // STREAM_RING
         AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
         AudioSystem.STREAM_ALARM,  // STREAM_ALARM
-        AudioSystem.STREAM_NOTIFICATION,  // STREAM_NOTIFICATION
+        AudioSystem.STREAM_RING,   // STREAM_NOTIFICATION
         AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
         AudioSystem.STREAM_SYSTEM,  // STREAM_SYSTEM_ENFORCED
         AudioSystem.STREAM_VOICE_CALL, // STREAM_DTMF
@@ -239,9 +242,6 @@
      */
     private int mVibrateSetting;
 
-    /** @see System#NOTIFICATIONS_USE_RING_VOLUME */
-    private int mNotificationsUseRingVolume;
-
     // Broadcast receiver for device connections intent broadcasts
     private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
 
@@ -371,7 +371,9 @@
 
         // Register for media button intent broadcasts.
         intentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
-        intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+        // Workaround for bug on priority setting
+        //intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+        intentFilter.setPriority(Integer.MAX_VALUE);
         context.registerReceiver(mMediaButtonReceiver, intentFilter);
 
         // Register for phone state monitoring
@@ -451,16 +453,6 @@
                 System.MUTE_STREAMS_AFFECTED,
                 ((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM)));
 
-        if (mVoiceCapable) {
-            mNotificationsUseRingVolume = System.getInt(cr,
-                    Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1);
-        } else {
-            mNotificationsUseRingVolume = 1;
-        }
-
-        if (mNotificationsUseRingVolume == 1) {
-            STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING;
-        }
         // Each stream will read its own persisted settings
 
         // Broadcast the sticky intent
@@ -885,7 +877,8 @@
                 requestAudioFocus(AudioManager.STREAM_RING,
                         AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb,
                         null /* IAudioFocusDispatcher allowed to be null only for this clientId */,
-                        IN_VOICE_COMM_FOCUS_ID /*clientId*/);
+                        IN_VOICE_COMM_FOCUS_ID /*clientId*/,
+                        "system");
 
             }
         }
@@ -897,7 +890,8 @@
             requestAudioFocus(AudioManager.STREAM_RING,
                     AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb,
                     null /* IAudioFocusDispatcher allowed to be null only for this clientId */,
-                    IN_VOICE_COMM_FOCUS_ID /*clientId*/);
+                    IN_VOICE_COMM_FOCUS_ID /*clientId*/,
+                    "system");
         }
         // if exiting call
         else if (newMode == AudioSystem.MODE_NORMAL) {
@@ -2155,6 +2149,33 @@
                     persistMediaButtonReceiver( (ComponentName) msg.obj );
                     break;
 
+                case MSG_RCDISPLAY_CLEAR:
+                    Log.i(TAG, "Clear remote control display");
+                    Intent clearIntent = new Intent(AudioManager.REMOTE_CONTROL_CLIENT_CHANGED);
+                    // no extra means no IRemoteControlClient, which is a request to clear
+                    clearIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                    mContext.sendBroadcast(clearIntent);
+                    break;
+
+                case MSG_RCDISPLAY_UPDATE:
+                    synchronized(mCurrentRcLock) {
+                        if (mCurrentRcClientRef.get() == null) {
+                            // the remote control display owner has changed between the
+                            // the message to update the display was sent, and the time it
+                            // gets to be processed (now)
+                        } else {
+                            mCurrentRcClientGen++;
+                            Log.i(TAG, "Display/update remote control ");
+                            Intent rcClientIntent = new Intent(
+                                    AudioManager.REMOTE_CONTROL_CLIENT_CHANGED);
+                            rcClientIntent.putExtra(AudioManager.EXTRA_REMOTE_CONTROL_CLIENT,
+                                    mCurrentRcClientGen);
+                            rcClientIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                            mContext.sendBroadcast(rcClientIntent);
+                        }
+                    }
+                    break;
+
                 case MSG_BT_HEADSET_CNCT_FAILED:
                     resetBluetoothSco();
                     break;
@@ -2168,8 +2189,6 @@
             super(new Handler());
             mContentResolver.registerContentObserver(Settings.System.getUriFor(
                 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
-            mContentResolver.registerContentObserver(Settings.System.getUriFor(
-                    Settings.System.NOTIFICATIONS_USE_RING_VOLUME), false, this);
         }
 
         @Override
@@ -2193,29 +2212,6 @@
                     mRingerModeAffectedStreams = ringerModeAffectedStreams;
                     setRingerModeInt(getRingerMode(), false);
                 }
-
-                int notificationsUseRingVolume = Settings.System.getInt(mContentResolver,
-                        Settings.System.NOTIFICATIONS_USE_RING_VOLUME,
-                        1);
-                if (mVoiceCapable) {
-                    if (notificationsUseRingVolume != mNotificationsUseRingVolume) {
-                        mNotificationsUseRingVolume = notificationsUseRingVolume;
-                        if (mNotificationsUseRingVolume == 1) {
-                            STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING;
-                            mStreamStates[AudioSystem.STREAM_NOTIFICATION].setVolumeIndexSettingName(
-                                    System.VOLUME_SETTINGS[AudioSystem.STREAM_RING]);
-                        } else {
-                            STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_NOTIFICATION;
-                            mStreamStates[AudioSystem.STREAM_NOTIFICATION].setVolumeIndexSettingName(
-                                    System.VOLUME_SETTINGS[AudioSystem.STREAM_NOTIFICATION]);
-                            // Persist notification volume volume as it was not persisted while aliased to ring volume
-                            //  and persist with no delay as there might be registered observers of the persisted
-                            //  notification volume.
-                            sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, AudioSystem.STREAM_NOTIFICATION,
-                                    SENDMSG_REPLACE, 1, 1, mStreamStates[AudioSystem.STREAM_NOTIFICATION], 0);
-                        }
-                    }
-                }
             }
         }
     }
@@ -2567,23 +2563,25 @@
 
     private static class FocusStackEntry {
         public int mStreamType = -1;// no stream type
-        public boolean mIsTransportControlReceiver = false;
         public IAudioFocusDispatcher mFocusDispatcher = null;
         public IBinder mSourceRef = null;
         public String mClientId;
         public int mFocusChangeType;
+        public String mPackageName;
+        public int mCallingUid;
 
         public FocusStackEntry() {
         }
 
-        public FocusStackEntry(int streamType, int duration, boolean isTransportControlReceiver,
-                IAudioFocusDispatcher afl, IBinder source, String id) {
+        public FocusStackEntry(int streamType, int duration,
+                IAudioFocusDispatcher afl, IBinder source, String id, String pn, int uid) {
             mStreamType = streamType;
-            mIsTransportControlReceiver = isTransportControlReceiver;
             mFocusDispatcher = afl;
             mSourceRef = source;
             mClientId = id;
             mFocusChangeType = duration;
+            mPackageName = pn;
+            mCallingUid = uid;
         }
     }
 
@@ -2600,13 +2598,15 @@
             while(stackIterator.hasNext()) {
                 FocusStackEntry fse = stackIterator.next();
                 pw.println("     source:" + fse.mSourceRef + " -- client: " + fse.mClientId
-                        + " -- duration: " +fse.mFocusChangeType);
+                        + " -- duration: " + fse.mFocusChangeType
+                        + " -- uid: " + fse.mCallingUid);
             }
         }
     }
 
     /**
      * Helper function:
+     * Called synchronized on mAudioFocusLock
      * Remove a focus listener from the focus stack.
      * @param focusListenerToRemove the focus listener
      * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding
@@ -2621,6 +2621,10 @@
             if (signal) {
                 // notify the new top of the stack it gained focus
                 notifyTopOfAudioFocusStack();
+                // there's a new top of the stack, let the remote control know
+                synchronized(mRCStack) {
+                    checkUpdateRemoteControlDisplay();
+                }
             }
         } else {
             // focus is abandoned by a client that's not at the top of the stack,
@@ -2639,6 +2643,7 @@
 
     /**
      * Helper function:
+     * Called synchronized on mAudioFocusLock
      * Remove focus listeners from the focus stack for a particular client.
      */
     private void removeFocusStackEntryForClient(IBinder cb) {
@@ -2658,6 +2663,10 @@
             // we removed an entry at the top of the stack:
             //  notify the new top of the stack it gained focus.
             notifyTopOfAudioFocusStack();
+            // there's a new top of the stack, let the remote control know
+            synchronized(mRCStack) {
+                checkUpdateRemoteControlDisplay();
+            }
         }
     }
 
@@ -2700,7 +2709,7 @@
 
     /** @see AudioManager#requestAudioFocus(IAudioFocusDispatcher, int, int) */
     public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb,
-            IAudioFocusDispatcher fd, String clientId) {
+            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
         Log.i(TAG, " AudioFocus  requestAudioFocus() from " + clientId);
         // the main stream type for the audio focus request is currently not used. It may
         // potentially be used to handle multiple stream type-dependent audio focuses.
@@ -2743,8 +2752,13 @@
             removeFocusStackEntry(clientId, false);
 
             // push focus requester at the top of the audio focus stack
-            mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, false, fd, cb,
-                    clientId));
+            mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, fd, cb,
+                    clientId, callingPackageName, Binder.getCallingUid()));
+
+            // there's a new top of the stack, let the remote control know
+            synchronized(mRCStack) {
+                checkUpdateRemoteControlDisplay();
+            }
         }//synchronized(mAudioFocusLock)
 
         // handle the potential premature death of the new holder of the focus
@@ -2831,19 +2845,134 @@
         }
     }
 
-    private static class RemoteControlStackEntry {
-        public ComponentName mReceiverComponent;// always non null
-        // TODO implement registration expiration?
-        //public int mRegistrationTime;
+    private final Object mCurrentRcLock = new Object();
+    /**
+     * The one remote control client to be polled for display information.
+     * This object is never null, but its reference might.
+     * Access protected by mCurrentRcLock.
+     */
+    private SoftReference<IRemoteControlClient> mCurrentRcClientRef =
+            new SoftReference<IRemoteControlClient>(null);
 
-        public RemoteControlStackEntry() {
-        }
+    private final static int RC_INFO_NONE = 0;
+    private final static int RC_INFO_ALL =
+        AudioManager.RemoteControlParameters.FLAG_INFORMATION_CHANGED_ALBUM_ART |
+        AudioManager.RemoteControlParameters.FLAG_INFORMATION_CHANGED_KEY_MEDIA |
+        AudioManager.RemoteControlParameters.FLAG_INFORMATION_CHANGED_METADATA |
+        AudioManager.RemoteControlParameters.FLAG_INFORMATION_CHANGED_PLAYSTATE;
 
-        public RemoteControlStackEntry(ComponentName r) {
-            mReceiverComponent = r;
+    /**
+     * The flags indicating what type of information changed since the last time it was queried.
+     * Access protected by mCurrentRcLock.
+     */
+    private int mCurrentRcClientInfoFlags = RC_INFO_ALL;
+
+    /**
+     * A monotonically increasing generation counter for mCurrentRcClientRef.
+     * Only accessed with a lock on mCurrentRcLock.
+     */
+    private int mCurrentRcClientGen = 0;
+
+    /**
+     * Returns the current remote control client.
+     * @param rcClientId the counter value that matches the extra
+     *     {@link AudioManager#EXTRA_REMOTE_CONTROL_CLIENT} in the
+     *     {@link AudioManager#REMOTE_CONTROL_CLIENT_CHANGED} event
+     * @return the current IRemoteControlClient from which information to display on the remote
+     *     control can be retrieved, or null if rcClientId doesn't match the current generation
+     *     counter.
+     */
+    public IRemoteControlClient getRemoteControlClient(int rcClientId) {
+        synchronized(mCurrentRcLock) {
+            if (rcClientId == mCurrentRcClientGen) {
+                return mCurrentRcClientRef.get();
+            } else {
+                return null;
+            }
         }
     }
 
+    /**
+     * Returns the current flags of information that changed on the current remote control client.
+     * Requesting this information clears it.
+     * @param rcClientId the counter value that matches the extra
+     *     {@link AudioManager#EXTRA_REMOTE_CONTROL_CLIENT} in the
+     *     {@link AudioManager#REMOTE_CONTROL_CLIENT_CHANGED} event
+     * @return the flags indicating which type of information changed since the client notified
+     *     that its information had changed.
+     */
+    public int getRemoteControlClientInformationChangedFlags(int rcClientId) {
+        synchronized(mCurrentRcLock) {
+            if (rcClientId == mCurrentRcClientGen) {
+                int flags = mCurrentRcClientInfoFlags;
+                mCurrentRcClientInfoFlags = RC_INFO_NONE;
+                return flags;
+            } else {
+                return RC_INFO_NONE;
+            }
+        }
+    }
+
+    /**
+     * Inner class to monitor remote control client deaths, and remove the client for the
+     * remote control stack if necessary.
+     */
+    private class RcClientDeathHandler implements IBinder.DeathRecipient {
+        private IBinder mCb; // To be notified of client's death
+        private ComponentName mRcEventReceiver;
+
+        RcClientDeathHandler(IBinder cb, ComponentName eventReceiver) {
+            mCb = cb;
+            mRcEventReceiver = eventReceiver;
+        }
+
+        public void binderDied() {
+            Log.w(TAG, "  RemoteControlClient died");
+            // remote control client died, make sure the displays don't use it anymore
+            //  by setting its remote control client to null
+            registerRemoteControlClient(mRcEventReceiver, null, null/*ignored*/);
+        }
+
+        public IBinder getBinder() {
+            return mCb;
+        }
+    }
+
+    private static class RemoteControlStackEntry {
+        /** the target for the ACTION_MEDIA_BUTTON events */
+        public ComponentName mReceiverComponent;// always non null
+        public String mCallingPackageName;
+        public int mCallingUid;
+
+        /** provides access to the information to display on the remote control */
+        public SoftReference<IRemoteControlClient> mRcClientRef;
+        public RcClientDeathHandler mRcClientDeathHandler;
+
+        public RemoteControlStackEntry(ComponentName r) {
+            mReceiverComponent = r;
+            mCallingUid = -1;
+            mRcClientRef = new SoftReference<IRemoteControlClient>(null);
+        }
+
+        public void unlinkToRcClientDeath() {
+            if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) {
+                try {
+                    mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0);
+                } catch (java.util.NoSuchElementException e) {
+                    // not much we can do here
+                    Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()");
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    /**
+     *  The stack of remote control event receivers.
+     *  Code sections and methods that modify the remote control event receiver stack are
+     *  synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either
+     *  stack, audio focus or RC, can lead to a change in the remote control display
+     */
     private Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>();
 
     /**
@@ -2855,8 +2984,10 @@
         synchronized(mRCStack) {
             Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
             while(stackIterator.hasNext()) {
-                RemoteControlStackEntry fse = stackIterator.next();
-                pw.println("     receiver:" + fse.mReceiverComponent);
+                RemoteControlStackEntry rcse = stackIterator.next();
+                pw.println("     receiver: " + rcse.mReceiverComponent +
+                        "  -- client: " + rcse.mRcClientRef.get() +
+                        "  -- uid: " + rcse.mCallingUid);
             }
         }
     }
@@ -2909,6 +3040,7 @@
             ComponentName receiverComponentName = ComponentName.unflattenFromString(receiverName);
             registerMediaButtonEventReceiver(receiverComponentName);
         }
+        // upon restoring (e.g. after boot), do we want to refresh all remotes?
     }
 
     /**
@@ -2921,14 +3053,20 @@
             return;
         }
         Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+        RemoteControlStackEntry rcse = null;
+        boolean wasInsideStack = false;
         while(stackIterator.hasNext()) {
-            RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
+            rcse = (RemoteControlStackEntry)stackIterator.next();
             if(rcse.mReceiverComponent.equals(newReceiver)) {
+                wasInsideStack = true;
                 stackIterator.remove();
                 break;
             }
         }
-        mRCStack.push(new RemoteControlStackEntry(newReceiver));
+        if (!wasInsideStack) {
+            rcse = new RemoteControlStackEntry(newReceiver);
+        }
+        mRCStack.push(rcse);
 
         // post message to persist the default media button receiver
         mAudioHandler.sendMessage( mAudioHandler.obtainMessage(
@@ -2950,13 +3088,93 @@
         }
     }
 
+    /**
+     * Helper function:
+     * Called synchronized on mRCStack
+     */
+    private boolean isCurrentRcController(ComponentName eventReceiver) {
+        if (!mRCStack.empty() && mRCStack.peek().mReceiverComponent.equals(eventReceiver)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Helper function:
+     * Called synchronized on mRCStack
+     */
+    private void clearRemoteControlDisplay() {
+        synchronized(mCurrentRcLock) {
+            mCurrentRcClientRef.clear();
+            mCurrentRcClientInfoFlags = RC_INFO_NONE;
+        }
+        mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) );
+    }
+
+    /**
+     * Helper function:
+     * Called synchronized on mRCStack
+     * mRCStack.empty() is false
+     */
+    private void updateRemoteControlDisplay() {
+        RemoteControlStackEntry rcse = mRCStack.peek();
+        // this is where we enforce opt-in for information display on the remote controls
+        //   with the new AudioManager.registerRemoteControlClient() API
+        if (rcse.mRcClientRef.get() == null) {
+            // FIXME remove log before release: this warning will be displayed for every AF change
+            Log.w(TAG, "Can't update remote control display with null remote control client");
+            clearRemoteControlDisplay();
+            return;
+        }
+        synchronized(mCurrentRcLock) {
+            if (!mCurrentRcClientRef.get().equals(rcse.mRcClientRef.get())) {
+                // new RC client, assume every type of information shall be queried
+                mCurrentRcClientInfoFlags = RC_INFO_ALL;
+            }
+            mCurrentRcClientRef = rcse.mRcClientRef;
+        }
+        mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_UPDATE, 0, 0, rcse) );
+    }
+
+    /**
+     * Helper function:
+     * Called synchronized on mFocusLock, then mRCStack
+     * Check whether the remote control display should be updated, triggers the update if required
+     */
+    private void checkUpdateRemoteControlDisplay() {
+        // determine whether the remote control display should be refreshed
+        // if either stack is empty, there is a mismatch, so clear the RC display
+        if (mRCStack.isEmpty() || mFocusStack.isEmpty()) {
+            clearRemoteControlDisplay();
+            return;
+        }
+        // if the top of the two stacks belong to different packages, there is a mismatch, clear
+        if ((mRCStack.peek().mCallingPackageName != null)
+                && (mFocusStack.peek().mPackageName != null)
+                && !(mRCStack.peek().mCallingPackageName.compareTo(
+                        mFocusStack.peek().mPackageName) == 0)) {
+            clearRemoteControlDisplay();
+            return;
+        }
+        // if the audio focus didn't originate from the same Uid as the one in which the remote
+        //   control information will be retrieved, clear
+        if (mRCStack.peek().mCallingUid != mFocusStack.peek().mCallingUid) {
+            clearRemoteControlDisplay();
+            return;
+        }
+        // refresh conditions were verified: update the remote controls
+        updateRemoteControlDisplay();
+    }
 
     /** see AudioManager.registerMediaButtonEventReceiver(ComponentName eventReceiver) */
     public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
         Log.i(TAG, "  Remote Control   registerMediaButtonEventReceiver() for " + eventReceiver);
 
-        synchronized(mRCStack) {
-            pushMediaButtonReceiver(eventReceiver);
+        synchronized(mAudioFocusLock) {
+            synchronized(mRCStack) {
+                pushMediaButtonReceiver(eventReceiver);
+                checkUpdateRemoteControlDisplay();
+            }
         }
     }
 
@@ -2964,11 +3182,80 @@
     public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
         Log.i(TAG, "  Remote Control   unregisterMediaButtonEventReceiver() for " + eventReceiver);
 
-        synchronized(mRCStack) {
-            removeMediaButtonReceiver(eventReceiver);
+        synchronized(mAudioFocusLock) {
+            synchronized(mRCStack) {
+                boolean topOfStackWillChange = isCurrentRcController(eventReceiver);
+                removeMediaButtonReceiver(eventReceiver);
+                if (topOfStackWillChange) {
+                    checkUpdateRemoteControlDisplay();
+                }
+            }
         }
     }
 
+    /** see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) */
+    public void registerRemoteControlClient(ComponentName eventReceiver,
+            IRemoteControlClient rcClient, String callingPackageName) {
+        synchronized(mAudioFocusLock) {
+            synchronized(mRCStack) {
+                // store the new display information
+                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+                while(stackIterator.hasNext()) {
+                    RemoteControlStackEntry rcse = stackIterator.next();
+                    if(rcse.mReceiverComponent.equals(eventReceiver)) {
+                        // already had a remote control client?
+                        if (rcse.mRcClientDeathHandler != null) {
+                            // stop monitoring the old client's death
+                            rcse.unlinkToRcClientDeath();
+                        }
+                        // save the new remote control client
+                        rcse.mRcClientRef = new SoftReference<IRemoteControlClient>(rcClient);
+                        rcse.mCallingPackageName = callingPackageName;
+                        rcse.mCallingUid = Binder.getCallingUid();
+                        if (rcClient == null) {
+                            break;
+                        }
+                        // monitor the new client's death
+                        IBinder b = rcClient.asBinder();
+                        RcClientDeathHandler rcdh =
+                                new RcClientDeathHandler(b, rcse.mReceiverComponent);
+                        try {
+                            b.linkToDeath(rcdh, 0);
+                        } catch (RemoteException e) {
+                            // remote control client is DOA, disqualify it
+                            Log.w(TAG, "registerRemoteControlClient() has a dead client " + b);
+                            rcse.mRcClientRef.clear();
+                        }
+                        rcse.mRcClientDeathHandler = rcdh;
+                        break;
+                    }
+                }
+                // if the eventReceiver is at the top of the stack
+                // then check for potential refresh of the remote controls
+                if (isCurrentRcController(eventReceiver)) {
+                    checkUpdateRemoteControlDisplay();
+                }
+            }
+        }
+    }
+
+    /** see AudioManager.notifyRemoteControlInformationChanged(ComponentName er, int infoFlag) */
+    public void notifyRemoteControlInformationChanged(ComponentName eventReceiver, int infoFlag) {
+        synchronized(mAudioFocusLock) {
+            synchronized(mRCStack) {
+                // only refresh if the eventReceiver is at the top of the stack
+                if (isCurrentRcController(eventReceiver)) {
+                    // there is a refresh request for the current event receiver: it might not be
+                    // displayed on the remote control display, but we can cache what new
+                    // information has changed.
+                    synchronized(mCurrentRcLock) {
+                        mCurrentRcClientInfoFlags |= infoFlag;
+                    }
+                    checkUpdateRemoteControlDisplay();
+                }
+            }
+        }
+    }
 
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index e3bd7b4..1061f13 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -18,6 +18,9 @@
 
 import android.content.ComponentName;
 import android.media.IAudioFocusDispatcher;
+import android.media.IRemoteControlClient;
+import android.net.Uri;
+import android.os.Bundle;
 
 /**
  * {@hide}
@@ -77,7 +80,7 @@
     boolean isBluetoothScoOn();
 
     int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb, IAudioFocusDispatcher l,
-            String clientId);
+            String clientId, String callingPackageName);
 
     int abandonAudioFocus(IAudioFocusDispatcher l, String clientId);
     
@@ -87,6 +90,15 @@
 
     void unregisterMediaButtonEventReceiver(in ComponentName eventReceiver);
 
+    void registerRemoteControlClient(in ComponentName eventReceiver,
+           in IRemoteControlClient rcClient, in String callingPackageName);
+
+    IRemoteControlClient getRemoteControlClient(in int rcClientId);
+
+    int getRemoteControlClientInformationChangedFlags(in int rcClientId);
+
+    void notifyRemoteControlInformationChanged(in ComponentName eventReceiver, int infoFlag);
+
     void startBluetoothSco(IBinder cb);
 
     void stopBluetoothSco(IBinder cb);
diff --git a/media/java/android/media/IRemoteControlClient.aidl b/media/java/android/media/IRemoteControlClient.aidl
new file mode 100644
index 0000000..a49371c
--- /dev/null
+++ b/media/java/android/media/IRemoteControlClient.aidl
@@ -0,0 +1,76 @@
+/*
+ * 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 android.media;
+
+import android.graphics.Bitmap;
+
+/**
+ * {@hide}
+ */
+interface IRemoteControlClient
+{
+    /**
+     * Called by a remote control to retrieve a String of information to display.
+     * @param field the identifier for a metadata field to retrieve. Valid values are
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
+     * @return null if the given field is not supported, or the String matching the metadata field.
+     */
+    String getMetadataString(int field);
+
+    /**
+     * Returns the current playback state.
+     * @return one of the following values:
+     *       {@link android.media.AudioManager.RemoteControl#PLAYSTATE_STOPPED},
+     *       {@link android.media.AudioManager.RemoteControl#PLAYSTATE_PAUSED},
+     *       {@link android.media.AudioManager.RemoteControl#PLAYSTATE_PLAYING},
+     *       {@link android.media.AudioManager.RemoteControl#PLAYSTATE_FAST_FORWARDING},
+     *       {@link android.media.AudioManager.RemoteControl#PLAYSTATE_REWINDING},
+     *       {@link android.media.AudioManager.RemoteControl#PLAYSTATE_SKIPPING_FORWARDS},
+     *       {@link android.media.AudioManager.RemoteControl#PLAYSTATE_SKIPPING_BACKWARDS},
+     *       {@link android.media.AudioManager.RemoteControl#PLAYSTATE_BUFFERING}.
+     */
+    int getPlaybackState();
+
+    /**
+     * Returns the flags for the media transport control buttons this client supports.
+     * @see {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_PREVIOUS},
+     *      {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_REWIND},
+     *      {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_PLAY},
+     *      {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_PLAY_PAUSE},
+     *      {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_PAUSE},
+     *      {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_STOP},
+     *      {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_FAST_FORWARD},
+     *      {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_NEXT}
+     */
+    int getTransportControlFlags();
+
+    Bitmap getAlbumArt(int width, int height);
+}
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 8339e4b..02017a1 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -307,7 +307,7 @@
     private Uri mThumbsUri;
     private Uri mPlaylistsUri;
     private Uri mFilesUri;
-    private boolean mProcessPlaylists;
+    private boolean mProcessPlaylists, mProcessGenres;
     private int mMtpObjectHandle;
 
     private final String mExternalStoragePath;
@@ -612,7 +612,8 @@
                 mAlbum = value.trim();
             } else if (name.equalsIgnoreCase("composer") || name.startsWith("composer;")) {
                 mComposer = value.trim();
-            } else if (name.equalsIgnoreCase("genre") || name.startsWith("genre;")) {
+            } else if (mProcessGenres &&
+                    (name.equalsIgnoreCase("genre") || name.startsWith("genre;"))) {
                 mGenre = getGenreName(value);
             } else if (name.equalsIgnoreCase("year") || name.startsWith("year;")) {
                 mYear = parseSubstring(value, 0, 0);
@@ -1151,6 +1152,7 @@
         if (!volumeName.equals("internal")) {
             // we only support playlists on external media
             mProcessPlaylists = true;
+            mProcessGenres = true;
             mPlaylistsUri = Playlists.getContentUri(volumeName);
 
             mCaseInsensitivePaths = true;
diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java
index 7c181ee..078d4af 100644
--- a/media/java/android/media/ThumbnailUtils.java
+++ b/media/java/android/media/ThumbnailUtils.java
@@ -387,6 +387,7 @@
             if (recycle) {
                 source.recycle();
             }
+            c.setBitmap(null);
             return b2;
         }
         float bitmapWidthF = source.getWidth();
diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
index 6b0fb12..5bfdcdb 100644
--- a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
+++ b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
@@ -3761,6 +3761,7 @@
             final Canvas canvas = new Canvas(bitmap);
             canvas.drawBitmap(tempBitmap, new Rect(0, 0, newWidth, newHeight),
                                           new Rect(0, 0, width, height), sResizePaint);
+            canvas.setBitmap(null);
         }
 
         if (tempBitmap != null) {
@@ -3837,6 +3838,7 @@
                 final Canvas canvas = new Canvas(bitmaps[i]);
                 canvas.drawBitmap(tempBitmap, new Rect(0, 0, newWidth, newHeight),
                                               new Rect(0, 0, width, height), sResizePaint);
+                canvas.setBitmap(null);
             }
         }
 
diff --git a/media/java/android/media/videoeditor/MediaImageItem.java b/media/java/android/media/videoeditor/MediaImageItem.java
index 73cc7e2..f0cc1fe 100755
--- a/media/java/android/media/videoeditor/MediaImageItem.java
+++ b/media/java/android/media/videoeditor/MediaImageItem.java
@@ -1008,6 +1008,7 @@
                                               srcBitmap.getHeight()),
                                               new Rect(0, 0, (int)bitmapWidth,
                                               (int)bitmapHeight), sResizePaint);
+        canvas.setBitmap(null);
         /**
          *  Release the source bitmap
          */
diff --git a/media/java/android/media/videoeditor/OverlayFrame.java b/media/java/android/media/videoeditor/OverlayFrame.java
index 131f5f0..d159df2 100755
--- a/media/java/android/media/videoeditor/OverlayFrame.java
+++ b/media/java/android/media/videoeditor/OverlayFrame.java
@@ -420,6 +420,7 @@
             }
 
             overlayCanvas.drawBitmap(overlayBitmap, srcRect, destRect, sResizePaint);
+            overlayCanvas.setBitmap(null);
 
             /*
              * Write to the dest file
diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
index 4203b6e..a5a6b64 100644
--- a/media/libstagefright/AACExtractor.cpp
+++ b/media/libstagefright/AACExtractor.cpp
@@ -92,7 +92,7 @@
     size_t frameSize = 0;
 
     uint8_t syncword[2];
-    if (source->readAt(0, &syncword, 2) != 2) {
+    if (source->readAt(offset, &syncword, 2) != 2) {
         return 0;
     }
     if ((syncword[0] != 0xff) || ((syncword[1] & 0xf6) != 0xf0)) {
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
index a8fadf2..0b14f1e 100644
--- a/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/MediaBuffer.cpp
@@ -21,6 +21,7 @@
 #include <pthread.h>
 #include <stdlib.h>
 
+#include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MetaData.h>
@@ -70,6 +71,20 @@
       mOriginal(NULL) {
 }
 
+MediaBuffer::MediaBuffer(const sp<ABuffer> &buffer)
+    : mObserver(NULL),
+      mNextBuffer(NULL),
+      mRefCount(0),
+      mData(buffer->data()),
+      mSize(buffer->size()),
+      mRangeOffset(0),
+      mRangeLength(mSize),
+      mBuffer(buffer),
+      mOwnsData(false),
+      mMetaData(new MetaData),
+      mOriginal(NULL) {
+}
+
 void MediaBuffer::release() {
     if (mObserver == NULL) {
         CHECK_EQ(mRefCount, 0);
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index ac73351..a4f3922 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -976,11 +976,6 @@
     video_def->nFrameWidth = width;
     video_def->nFrameHeight = height;
     video_def->xFramerate = 0;      // No need for output port
-    // FIXME:
-    // Revmoe this workaround after work is done.
-    if (!strncmp(mComponentName, "OMX.TI.DUCATI1", 14)) {
-        video_def->xFramerate = (frameRate << 16);
-    }
     video_def->nBitrate = bitRate;  // Q16 format
     video_def->eCompressionFormat = compressionFormat;
     video_def->eColorFormat = OMX_COLOR_FormatUnused;
diff --git a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
index 07a9eb8..887fe7c 100644
--- a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
+++ b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
@@ -47,6 +47,8 @@
     delete mDelegate;
     mDelegate = NULL;
 
+    clearDRMState_l();
+
     if (mDrmManagerClient != NULL) {
         delete mDrmManagerClient;
         mDrmManagerClient = NULL;
@@ -116,8 +118,6 @@
     // mURI.clear();
 
     mIOResult = err;
-
-    clearDRMState_l();
 }
 
 void ChromiumHTTPDataSource::disconnect() {
@@ -251,8 +251,6 @@
     // mURI.clear();
 
     mCondition.broadcast();
-
-    clearDRMState_l();
 }
 
 sp<DecryptHandle> ChromiumHTTPDataSource::DrmInitialization() {
diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp
index eb10ab7..26c3eda 100644
--- a/media/libstagefright/chromium_http/support.cpp
+++ b/media/libstagefright/chromium_http/support.cpp
@@ -183,19 +183,19 @@
 
 void SfDelegate::OnReceivedRedirect(
             net::URLRequest *request, const GURL &new_url, bool *defer_redirect) {
-    MY_LOGI("OnReceivedRedirect");
+    MY_LOGV("OnReceivedRedirect");
 }
 
 void SfDelegate::OnAuthRequired(
             net::URLRequest *request, net::AuthChallengeInfo *auth_info) {
-    MY_LOGI("OnAuthRequired");
+    MY_LOGV("OnAuthRequired");
 
     inherited::OnAuthRequired(request, auth_info);
 }
 
 void SfDelegate::OnCertificateRequested(
             net::URLRequest *request, net::SSLCertRequestInfo *cert_request_info) {
-    MY_LOGI("OnCertificateRequested");
+    MY_LOGV("OnCertificateRequested");
 
     inherited::OnCertificateRequested(request, cert_request_info);
 }
@@ -208,7 +208,7 @@
 }
 
 void SfDelegate::OnGetCookies(net::URLRequest *request, bool blocked_by_policy) {
-    MY_LOGI("OnGetCookies");
+    MY_LOGV("OnGetCookies");
 }
 
 void SfDelegate::OnSetCookie(
@@ -216,7 +216,7 @@
         const std::string &cookie_line,
         const net::CookieOptions &options,
         bool blocked_by_policy) {
-    MY_LOGI("OnSetCookie");
+    MY_LOGV("OnSetCookie");
 }
 
 void SfDelegate::OnResponseStarted(net::URLRequest *request) {
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 2578d2d..f67cdac 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -617,23 +617,32 @@
             goto rinse_repeat;
         }
 
-        if (!mPlaylist->isComplete()
-                && mSeqNumber > lastSeqNumberInPlaylist
-                && mNumRetries < kMaxNumRetries) {
+        if (!mPlaylist->isComplete() && mNumRetries < kMaxNumRetries) {
             ++mNumRetries;
 
-            mLastPlaylistFetchTimeUs = -1;
-            postMonitorQueue(3000000ll);
+            if (mSeqNumber > lastSeqNumberInPlaylist) {
+                mLastPlaylistFetchTimeUs = -1;
+                postMonitorQueue(3000000ll);
+                return;
+            }
+
+            // we've missed the boat, let's start from the lowest sequence
+            // number available and signal a discontinuity.
+
+            LOGI("We've missed the boat, restarting playback.");
+            mSeqNumber = lastSeqNumberInPlaylist;
+            explicitDiscontinuity = true;
+
+            // fall through
+        } else {
+            LOGE("Cannot find sequence number %d in playlist "
+                 "(contains %d - %d)",
+                 mSeqNumber, firstSeqNumberInPlaylist,
+                 firstSeqNumberInPlaylist + mPlaylist->size() - 1);
+
+            mDataSource->queueEOS(ERROR_END_OF_STREAM);
             return;
         }
-
-        LOGE("Cannot find sequence number %d in playlist "
-             "(contains %d - %d)",
-             mSeqNumber, firstSeqNumberInPlaylist,
-             firstSeqNumberInPlaylist + mPlaylist->size() - 1);
-
-        mDataSource->queueEOS(ERROR_END_OF_STREAM);
-        return;
     }
 
     mNumRetries = 0;
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 59de17e..2e66a2c 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -105,12 +105,10 @@
             int64_t timeUs;
             CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
 
-            MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
+            MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
+
             mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
 
-            // hexdump(buffer->data(), buffer->size());
-
-            memcpy(mediaBuffer->data(), buffer->data(), buffer->size());
             *out = mediaBuffer;
             return OK;
         }
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index a02591f..4ecb92f 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -628,14 +628,12 @@
 
         updateNormalPlayTime_l(buffer);
 
-        MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
-
         int64_t timeUs;
         CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
 
+        MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
         mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
 
-        memcpy(mediaBuffer->data(), buffer->data(), buffer->size());
         *out = mediaBuffer;
 
         mBuffers.erase(mBuffers.begin());
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 3f547fd..4c7f84e 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -1073,6 +1073,15 @@
             return gl;
         }
 
+        public void purgeBuffers() {
+            mEgl.eglMakeCurrent(mEglDisplay,
+                    EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE,
+                    EGL10.EGL_NO_CONTEXT);
+            mEgl.eglMakeCurrent(mEglDisplay,
+                    mEglSurface, mEglSurface,
+                    mEglContext);
+        }
+
         /**
          * Display the current render surface.
          * @return false if the context has been lost.
@@ -1415,6 +1424,7 @@
                         if (LOG_RENDERER) {
                             Log.w("GLThread", "onSurfaceChanged(" + w + ", " + h + ")");
                         }
+                        mEglHelper.purgeBuffers();
                         mRenderer.onSurfaceChanged(gl, w, h);
                         sizeChanged = false;
                     }
diff --git a/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml b/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml
index 3668b8c..6504435 100644
--- a/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml
+++ b/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml
@@ -18,10 +18,22 @@
  */
 -->
 
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="fill_parent" 
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent" 
+              android:layout_height="match_parent"
+              android:orientation="vertical" >
+
+    <ScrollView
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:layout_width="match_parent"
+            android:padding="16dp"
+            android:clipToPadding="false" >
+
+        <LinearLayout
+                android:orientation="vertical"
                 android:layout_height="wrap_content"
-                android:padding="16dp" >
+                android:layout_width="match_parent">
 
     <TextView android:id="@+id/confirm_text"
               android:layout_width="match_parent" 
@@ -63,20 +75,36 @@
               android:layout_marginLeft="30dp"
               android:layout_below="@id/enc_password"
               android:layout_marginBottom="30dp" />
+        </LinearLayout>
+    </ScrollView>
 
-    <Button android:id="@+id/button_allow"
-            android:filterTouchesWhenObscured="true"
-            android:text="@string/allow_backup_button_label"
-            android:layout_below="@id/package_name"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content" />
+    <!-- button bar divider -->
+    <View android:background="?android:attr/dividerHorizontal"
+          android:layout_height="1dp"
+          android:layout_width="match_parent" />
+
+    <!-- button bar -->
+    <LinearLayout android:orientation="horizontal"
+                  style="?android:attr/buttonBarStyle"                 
+                  android:layout_height="wrap_content"
+                  android:layout_width="match_parent"
+                  android:layout_gravity="bottom">
 
     <Button android:id="@+id/button_deny"
+            style="?android:attr/buttonBarButtonStyle"
             android:text="@string/deny_backup_button_label"
-            android:layout_below="@id/package_name"
-            android:layout_toRightOf="@id/button_allow"
-            android:layout_alignTop="@id/button_allow"
             android:layout_height="wrap_content"
-            android:layout_width="wrap_content" />
+            android:layout_width="0dp"
+            android:layout_weight="1" />
 
-</RelativeLayout>
+    <Button android:id="@+id/button_allow"
+            style="?android:attr/buttonBarButtonStyle"
+            android:filterTouchesWhenObscured="true"
+            android:text="@string/allow_backup_button_label"
+            android:layout_height="wrap_content"
+            android:layout_width="0dp"
+            android:layout_weight="1" />
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml b/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml
index 38fcc49..3522e7c 100644
--- a/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml
+++ b/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml
@@ -18,65 +18,91 @@
  */
 -->
 
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="fill_parent" 
-                android:layout_height="wrap_content"
-                android:padding="16dp" >
-
-    <TextView android:id="@+id/confirm_text"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:layout_width="match_parent" 
-              android:layout_height="wrap_content"
-              android:layout_marginBottom="30dp"
-              android:text="@string/restore_confirm_text" />
+              android:layout_height="match_parent"
+              android:orientation="vertical"
+              android:padding="16dp" >
 
-    <TextView android:id="@+id/password_desc"
-              android:layout_below="@id/confirm_text"
-              android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:layout_marginBottom="10dp"
-              android:text="@string/current_password_text" />
+    <ScrollView 
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:layout_width="match_parent">
+        <LinearLayout
+                android:orientation="vertical"
+                android:layout_height="wrap_content"
+                android:layout_width="match_parent">
 
-    <EditText android:id="@+id/password"
-              android:layout_below="@id/password_desc"
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:layout_marginBottom="30dp"
-              android:password="true" />
+        <TextView android:id="@+id/confirm_text"
+                  android:layout_width="match_parent" 
+                  android:layout_height="wrap_content"
+                  android:layout_marginBottom="30dp"
+                  android:text="@string/restore_confirm_text" />
 
-    <TextView android:id="@+id/enc_password_desc"
-              android:layout_below="@id/password"
-              android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:layout_marginBottom="10dp"
-              android:text="@string/restore_enc_password_text" />
+        <TextView android:id="@+id/password_desc"
+                  android:layout_below="@id/confirm_text"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:layout_marginBottom="10dp"
+                  android:text="@string/current_password_text" />
 
-    <EditText android:id="@+id/enc_password"
-              android:layout_below="@id/enc_password_desc"
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:layout_marginBottom="30dp"
-              android:password="true" />
+        <EditText android:id="@+id/password"
+                  android:layout_below="@id/password_desc"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:layout_marginBottom="30dp"
+                  android:password="true" />
 
-    <TextView android:id="@+id/package_name"
-              android:layout_width="match_parent"
-              android:layout_height="20dp"
-              android:layout_marginLeft="30dp"
-              android:layout_below="@id/enc_password"
-              android:layout_marginBottom="30dp" />
+        <TextView android:id="@+id/enc_password_desc"
+                  android:layout_below="@id/password"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:layout_marginBottom="10dp"
+                  android:text="@string/restore_enc_password_text" />
 
-    <Button android:id="@+id/button_allow"
-            android:filterTouchesWhenObscured="true"
-            android:text="@string/allow_restore_button_label"
-            android:layout_below="@id/package_name"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content" />
+        <EditText android:id="@+id/enc_password"
+                  android:layout_below="@id/enc_password_desc"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:layout_marginBottom="30dp"
+                  android:password="true" />
 
-    <Button android:id="@+id/button_deny"
-            android:text="@string/deny_restore_button_label"
-            android:layout_below="@id/package_name"
-            android:layout_toRightOf="@id/button_allow"
-            android:layout_alignTop="@id/button_allow"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content" />
+        <TextView android:id="@+id/package_name"
+                  android:layout_width="match_parent"
+                  android:layout_height="20dp"
+                  android:layout_marginLeft="30dp"
+                  android:layout_below="@id/enc_password"
+                  android:layout_marginBottom="10dp" />
+        </LinearLayout>
+    </ScrollView>
 
-</RelativeLayout>
+    <!-- button bar divider -->
+    <View android:background="?android:attr/dividerHorizontal"
+          android:layout_height="1dp"
+          android:layout_width="match_parent" />
+
+    <!-- button bar -->
+    <LinearLayout android:orientation="horizontal"
+                  style="?android:attr/buttonBarStyle"                 
+                  android:layout_height="wrap_content"
+                  android:layout_width="match_parent"
+                  android:layout_gravity="bottom">
+
+        <Button android:id="@+id/button_deny"
+                style="?android:attr/buttonBarButtonStyle"
+                android:text="@string/deny_restore_button_label"
+                android:layout_height="wrap_content"
+                android:layout_width="0dp"
+                android:layout_weight="1" />
+
+        <Button android:id="@+id/button_allow"
+                style="?android:attr/buttonBarButtonStyle"
+                android:filterTouchesWhenObscured="true"
+                android:text="@string/allow_restore_button_label"
+                android:layout_height="wrap_content"
+                android:layout_width="0dp"
+                android:layout_weight="1" />
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
index f65a62f..5448e0b 100644
--- a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
+++ b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
@@ -48,6 +48,8 @@
     static final String TAG = "BackupRestoreConfirmation";
     static final boolean DEBUG = true;
 
+    static final String DID_ACKNOWLEDGE = "did_acknowledge";
+
     static final int MSG_START_BACKUP = 1;
     static final int MSG_BACKUP_PACKAGE = 2;
     static final int MSG_END_BACKUP = 3;
@@ -149,7 +151,13 @@
         mBackupManager = IBackupManager.Stub.asInterface(ServiceManager.getService(Context.BACKUP_SERVICE));
 
         mHandler = new ObserverHandler(getApplicationContext());
-        mObserver = new FullObserver();
+        final Object oldObserver = getLastNonConfigurationInstance();
+        if (oldObserver == null) {
+            mObserver = new FullObserver(mHandler);
+        } else {
+            mObserver = (FullObserver) oldObserver;
+            mObserver.setHandler(mHandler);
+        }
 
         setContentView(layoutId);
 
@@ -189,16 +197,24 @@
                 mDenyButton.setEnabled(false);
             }
         });
+
+        // if we're a relaunch we may need to adjust button enable state
+        if (icicle != null) {
+            mDidAcknowledge = icicle.getBoolean(DID_ACKNOWLEDGE, false);
+            mAllowButton.setEnabled(!mDidAcknowledge);
+            mDenyButton.setEnabled(!mDidAcknowledge);
+        }
+    }
+
+    // Preserve the restore observer callback binder across activity relaunch
+    @Override
+    public Object onRetainNonConfigurationInstance() {
+        return mObserver;
     }
 
     @Override
-    public void onStop() {
-        super.onStop();
-
-        // We explicitly equate departure from the UI with refusal.  This includes the
-        // implicit configuration-changed stop/restart cycle.
-        sendAcknowledgement(mToken, false, null);
-        finish();
+    protected void onSaveInstanceState(Bundle outState) {
+        outState.putBoolean(DID_ACKNOWLEDGE, mDidAcknowledge);
     }
 
     void sendAcknowledgement(int token, boolean allow, IFullBackupRestoreObserver observer) {
@@ -230,6 +246,16 @@
      * the notifications onto the main thread.
      */
     class FullObserver extends IFullBackupRestoreObserver.Stub {
+        private Handler mHandler;
+
+        public FullObserver(Handler h) {
+            mHandler = h;
+        }
+
+        public void setHandler(Handler h) {
+            mHandler = h;
+        }
+
         //
         // IFullBackupRestoreObserver implementation
         //
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 626cc86..eae6112 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -38,8 +38,7 @@
 import android.os.StatFs;
 import android.app.IntentService;
 import android.util.DisplayMetrics;
-import android.util.Log;
-import android.util.Pair;
+import android.util.Slog;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -47,11 +46,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipException;
-import java.util.zip.ZipFile;
 
 import android.os.FileUtils;
 import android.provider.Settings;
@@ -120,29 +114,39 @@
         public PackageInfoLite getMinimalPackageInfo(final Uri fileUri, int flags, long threshold) {
             PackageInfoLite ret = new PackageInfoLite();
             if (fileUri == null) {
-                Log.i(TAG, "Invalid package uri " + fileUri);
+                Slog.i(TAG, "Invalid package uri " + fileUri);
                 ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
                 return ret;
             }
             String scheme = fileUri.getScheme();
             if (scheme != null && !scheme.equals("file")) {
-                Log.w(TAG, "Falling back to installing on internal storage only");
+                Slog.w(TAG, "Falling back to installing on internal storage only");
                 ret.recommendedInstallLocation = PackageHelper.RECOMMEND_INSTALL_INTERNAL;
                 return ret;
             }
             String archiveFilePath = fileUri.getPath();
             DisplayMetrics metrics = new DisplayMetrics();
             metrics.setToDefaults();
+
             PackageParser.PackageLite pkg = PackageParser.parsePackageLite(archiveFilePath, 0);
             if (pkg == null) {
-                Log.w(TAG, "Failed to parse package");
-                ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
+                Slog.w(TAG, "Failed to parse package");
+
+                final File apkFile = new File(archiveFilePath);
+                if (!apkFile.exists()) {
+                    ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI;
+                } else {
+                    ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
+                }
+
                 return ret;
             }
             ret.packageName = pkg.packageName;
             ret.installLocation = pkg.installLocation;
+
             ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation,
                     archiveFilePath, flags, threshold);
+
             return ret;
         }
 
@@ -150,20 +154,28 @@
         public boolean checkInternalFreeStorage(Uri packageUri, long threshold)
                 throws RemoteException {
             final File apkFile = new File(packageUri.getPath());
-            return isUnderInternalThreshold(apkFile, threshold);
+            try {
+                return isUnderInternalThreshold(apkFile, threshold);
+            } catch (FileNotFoundException e) {
+                return true;
+            }
         }
 
         @Override
         public boolean checkExternalFreeStorage(Uri packageUri) throws RemoteException {
             final File apkFile = new File(packageUri.getPath());
-            return isUnderExternalThreshold(apkFile);
+            try {
+                return isUnderExternalThreshold(apkFile);
+            } catch (FileNotFoundException e) {
+                return true;
+            }
         }
 
         public ObbInfo getObbInfo(String filename) {
             try {
                 return ObbScanner.getObbInfo(filename);
             } catch (IOException e) {
-                Log.d(TAG, "Couldn't get OBB info for " + filename);
+                Slog.d(TAG, "Couldn't get OBB info for " + filename);
                 return null;
             }
         }
@@ -221,7 +233,7 @@
         // Make sure the sdcard is mounted.
         String status = Environment.getExternalStorageState();
         if (!status.equals(Environment.MEDIA_MOUNTED)) {
-            Log.w(TAG, "Make sure sdcard is mounted.");
+            Slog.w(TAG, "Make sure sdcard is mounted.");
             return null;
         }
 
@@ -229,75 +241,81 @@
         String codePath = packageURI.getPath();
         File codeFile = new File(codePath);
 
-        // Native files we need to copy to the container.
-        List<Pair<ZipEntry, String>> nativeFiles = new ArrayList<Pair<ZipEntry, String>>();
-
         // Calculate size of container needed to hold base APK.
-        final int sizeMb = calculateContainerSize(codeFile, nativeFiles);
+        int sizeMb;
+        try {
+            sizeMb = calculateContainerSize(codeFile);
+        } catch (FileNotFoundException e) {
+            Slog.w(TAG, "File does not exist when trying to copy " + codeFile.getPath());
+            return null;
+        }
 
         // Create new container
-        String newCachePath = null;
+        final String newCachePath;
         if ((newCachePath = PackageHelper.createSdDir(sizeMb, newCid, key, Process.myUid())) == null) {
-            Log.e(TAG, "Failed to create container " + newCid);
-            return null;
-        }
-        if (localLOGV)
-            Log.i(TAG, "Created container for " + newCid + " at path : " + newCachePath);
-        File resFile = new File(newCachePath, resFileName);
-        if (!FileUtils.copyFile(new File(codePath), resFile)) {
-            Log.e(TAG, "Failed to copy " + codePath + " to " + resFile);
-            // Clean up container
-            PackageHelper.destroySdDir(newCid);
+            Slog.e(TAG, "Failed to create container " + newCid);
             return null;
         }
 
-        try {
-            ZipFile zipFile = new ZipFile(codeFile);
+        if (localLOGV) {
+            Slog.i(TAG, "Created container for " + newCid + " at path : " + newCachePath);
+        }
 
-            File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME);
-            sharedLibraryDir.mkdir();
-
-            final int N = nativeFiles.size();
-            for (int i = 0; i < N; i++) {
-                final Pair<ZipEntry, String> entry = nativeFiles.get(i);
-
-                InputStream is = zipFile.getInputStream(entry.first);
-                try {
-                    File destFile = new File(sharedLibraryDir, entry.second);
-                    if (!FileUtils.copyToFile(is, destFile)) {
-                        throw new IOException("Couldn't copy native binary "
-                                + entry.first.getName() + " to " + entry.second);
-                    }
-                } finally {
-                    is.close();
-                }
+        final File resFile = new File(newCachePath, resFileName);
+        if (FileUtils.copyFile(new File(codePath), resFile)) {
+            if (localLOGV) {
+                Slog.i(TAG, "Copied " + codePath + " to " + resFile);
             }
-        } catch (IOException e) {
-            Log.e(TAG, "Couldn't copy native file to container", e);
+        } else {
+            Slog.e(TAG, "Failed to copy " + codePath + " to " + resFile);
+            // Clean up container
             PackageHelper.destroySdDir(newCid);
             return null;
         }
 
-        if (localLOGV) Log.i(TAG, "Copied " + codePath + " to " + resFile);
+        final File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME);
+        if (sharedLibraryDir.mkdir()) {
+            int ret = NativeLibraryHelper.copyNativeBinariesIfNeededLI(codeFile, sharedLibraryDir);
+            if (ret != PackageManager.INSTALL_SUCCEEDED) {
+                Slog.e(TAG, "Could not copy native libraries to " + sharedLibraryDir.getPath());
+                PackageHelper.destroySdDir(newCid);
+                return null;
+            }
+        } else {
+            Slog.e(TAG, "Could not create native lib directory: " + sharedLibraryDir.getPath());
+            PackageHelper.destroySdDir(newCid);
+            return null;
+        }
+
         if (!PackageHelper.finalizeSdDir(newCid)) {
-            Log.e(TAG, "Failed to finalize " + newCid + " at path " + newCachePath);
+            Slog.e(TAG, "Failed to finalize " + newCid + " at path " + newCachePath);
             // Clean up container
             PackageHelper.destroySdDir(newCid);
+            return null;
         }
-        if (localLOGV) Log.i(TAG, "Finalized container " + newCid);
+
+        if (localLOGV) {
+            Slog.i(TAG, "Finalized container " + newCid);
+        }
+
         if (PackageHelper.isContainerMounted(newCid)) {
-            if (localLOGV) Log.i(TAG, "Unmounting " + newCid +
-                    " at path " + newCachePath);
+            if (localLOGV) {
+                Slog.i(TAG, "Unmounting " + newCid + " at path " + newCachePath);
+            }
+
             // Force a gc to avoid being killed.
             Runtime.getRuntime().gc();
             PackageHelper.unMountSdDir(newCid);
         } else {
-            if (localLOGV) Log.i(TAG, "Container " + newCid + " not mounted");
+            if (localLOGV) {
+                Slog.i(TAG, "Container " + newCid + " not mounted");
+            }
         }
+
         return newCachePath;
     }
 
-    public static boolean copyToFile(InputStream inputStream, FileOutputStream out) {
+    private static boolean copyToFile(InputStream inputStream, FileOutputStream out) {
         try {
             byte[] buffer = new byte[4096];
             int bytesRead;
@@ -306,12 +324,12 @@
             }
             return true;
         } catch (IOException e) {
-            Log.i(TAG, "Exception : " + e + " when copying file");
+            Slog.i(TAG, "Exception : " + e + " when copying file");
             return false;
         }
     }
 
-    public static boolean copyToFile(File srcFile, FileOutputStream out) {
+    private static boolean copyToFile(File srcFile, FileOutputStream out) {
         InputStream inputStream = null;
         try {
             inputStream = new FileInputStream(srcFile);
@@ -323,7 +341,7 @@
         }
     }
 
-    private  boolean copyFile(Uri pPackageURI, FileOutputStream outStream) {
+    private boolean copyFile(Uri pPackageURI, FileOutputStream outStream) {
         String scheme = pPackageURI.getScheme();
         if (scheme == null || scheme.equals("file")) {
             final File srcPackageFile = new File(pPackageURI.getPath());
@@ -331,7 +349,7 @@
             // destination file in order to eliminate a window where the package directory
             // scanner notices the new package file but it's not completely copied yet.
             if (!copyToFile(srcPackageFile, outStream)) {
-                Log.e(TAG, "Couldn't copy file: " + srcPackageFile);
+                Slog.e(TAG, "Couldn't copy file: " + srcPackageFile);
                 return false;
             }
         } else if (scheme.equals("content")) {
@@ -339,28 +357,31 @@
             try {
                 fd = getContentResolver().openFileDescriptor(pPackageURI, "r");
             } catch (FileNotFoundException e) {
-                Log.e(TAG, "Couldn't open file descriptor from download service. Failed with exception " + e);
+                Slog.e(TAG,
+                        "Couldn't open file descriptor from download service. Failed with exception "
+                                + e);
                 return false;
             }
             if (fd == null) {
-                Log.e(TAG, "Couldn't open file descriptor from download service (null).");
+                Slog.e(TAG, "Couldn't open file descriptor from download service (null).");
                 return false;
             } else {
                 if (localLOGV) {
-                    Log.v(TAG, "Opened file descriptor from download service.");
+                    Slog.i(TAG, "Opened file descriptor from download service.");
                 }
                 ParcelFileDescriptor.AutoCloseInputStream
                 dlStream = new ParcelFileDescriptor.AutoCloseInputStream(fd);
                 // We copy the source package file to a temp file and then rename it to the
                 // destination file in order to eliminate a window where the package directory
-                // scanner notices the new package file but it's not completely copied yet.
+                // scanner notices the new package file but it's not completely
+                // cop
                 if (!copyToFile(dlStream, outStream)) {
-                    Log.e(TAG, "Couldn't copy " + pPackageURI + " to temp file.");
+                    Slog.e(TAG, "Couldn't copy " + pPackageURI + " to temp file.");
                     return false;
                 }
             }
         } else {
-            Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI);
+            Slog.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI);
             return false;
         }
         return true;
@@ -434,12 +455,20 @@
 
         boolean fitsOnInternal = false;
         if (checkBoth || prefer == PREFER_INTERNAL) {
-            fitsOnInternal = isUnderInternalThreshold(apkFile, threshold);
+            try {
+                fitsOnInternal = isUnderInternalThreshold(apkFile, threshold);
+            } catch (FileNotFoundException e) {
+                return PackageHelper.RECOMMEND_FAILED_INVALID_URI;
+            }
         }
 
         boolean fitsOnSd = false;
         if (!emulated && (checkBoth || prefer == PREFER_EXTERNAL)) {
-            fitsOnSd = isUnderExternalThreshold(apkFile);
+            try {
+                fitsOnSd = isUnderExternalThreshold(apkFile);
+            } catch (FileNotFoundException e) {
+                return PackageHelper.RECOMMEND_FAILED_INVALID_URI;
+            }
         }
 
         if (prefer == PREFER_INTERNAL) {
@@ -473,8 +502,20 @@
         }
     }
 
-    private boolean isUnderInternalThreshold(File apkFile, long threshold) {
+    /**
+     * Measure a file to see if it fits within the free space threshold.
+     *
+     * @param apkFile file to check
+     * @param threshold byte threshold to compare against
+     * @return true if file fits under threshold
+     * @throws FileNotFoundException when APK does not exist
+     */
+    private boolean isUnderInternalThreshold(File apkFile, long threshold)
+            throws FileNotFoundException {
         final long size = apkFile.length();
+        if (size == 0 && !apkFile.exists()) {
+            throw new FileNotFoundException();
+        }
 
         final StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath());
         final long availInternalSize = (long) internalStats.getAvailableBlocks()
@@ -484,12 +525,19 @@
     }
 
 
-    private boolean isUnderExternalThreshold(File apkFile) {
+    /**
+     * Measure a file to see if it fits in the external free space.
+     *
+     * @param apkFile file to check
+     * @return true if file fits
+     * @throws IOException when file does not exist
+     */
+    private boolean isUnderExternalThreshold(File apkFile) throws FileNotFoundException {
         if (Environment.isExternalStorageEmulated()) {
             return false;
         }
 
-        final int sizeMb = calculateContainerSize(apkFile, null);
+        final int sizeMb = calculateContainerSize(apkFile);
 
         final int availSdMb;
         if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
@@ -508,10 +556,14 @@
      * 
      * @param apkFile file from which to calculate size
      * @return size in megabytes (2^20 bytes)
+     * @throws FileNotFoundException when file does not exist
      */
-    private int calculateContainerSize(File apkFile, List<Pair<ZipEntry, String>> outFiles) {
+    private int calculateContainerSize(File apkFile) throws FileNotFoundException {
         // Calculate size of container needed to hold base APK.
         long sizeBytes = apkFile.length();
+        if (sizeBytes == 0 && !apkFile.exists()) {
+            throw new FileNotFoundException();
+        }
 
         // Check all the native files that need to be copied and add that to the
         // container size.
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index f527447..f4890e0 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -907,20 +907,12 @@
         if (upgradeVersion == 68) {
             // Enable all system sounds by default
             db.beginTransaction();
-            SQLiteStatement stmt = null;
             try {
-                stmt = db.compileStatement("INSERT OR REPLACE INTO system(name,value)"
-                        + " VALUES(?,?);");
-                loadDefaultHapticSettings(stmt);
-                loadUISoundEffectsSettings(stmt);
                 db.execSQL("DELETE FROM system WHERE name='"
                         + Settings.System.NOTIFICATIONS_USE_RING_VOLUME + "'");
-                stmt.close();
                 db.setTransactionSuccessful();
             } finally {
                 db.endTransaction();
-                if (stmt != null)
-                    stmt.close();
             }
             upgradeVersion = 69;
         }
diff --git a/core/res/res/anim/priority_alert_enter.xml b/packages/SystemUI/res/anim/priority_alert_enter.xml
similarity index 100%
rename from core/res/res/anim/priority_alert_enter.xml
rename to packages/SystemUI/res/anim/priority_alert_enter.xml
diff --git a/core/res/res/anim/priority_alert_exit.xml b/packages/SystemUI/res/anim/priority_alert_exit.xml
similarity index 100%
rename from core/res/res/anim/priority_alert_exit.xml
rename to packages/SystemUI/res/anim/priority_alert_exit.xml
diff --git a/core/res/res/anim/status_bar_enter.xml b/packages/SystemUI/res/anim/status_bar_enter.xml
similarity index 87%
rename from core/res/res/anim/status_bar_enter.xml
rename to packages/SystemUI/res/anim/status_bar_enter.xml
index 1a1dc9b..f1c1301 100644
--- a/core/res/res/anim/status_bar_enter.xml
+++ b/packages/SystemUI/res/anim/status_bar_enter.xml
@@ -18,7 +18,8 @@
 */
 -->
 
-<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@interpolator/decelerate_quad">
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@android:interpolator/decelerate_quad">
 	<translate android:fromYDelta="-75%" android:toYDelta="0"
         android:duration="@android:integer/config_mediumAnimTime"/>
 	<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
diff --git a/core/res/res/anim/status_bar_exit.xml b/packages/SystemUI/res/anim/status_bar_exit.xml
similarity index 88%
rename from core/res/res/anim/status_bar_exit.xml
rename to packages/SystemUI/res/anim/status_bar_exit.xml
index 1f71090..46462e2 100644
--- a/core/res/res/anim/status_bar_exit.xml
+++ b/packages/SystemUI/res/anim/status_bar_exit.xml
@@ -18,7 +18,8 @@
 */
 -->
 
-<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@interpolator/accelerate_quad">
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@android:interpolator/accelerate_quad">
 	<translate android:fromYDelta="0" android:toYDelta="-75%"
         android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime"/>
 	<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar.xml b/packages/SystemUI/res/layout-sw600dp/status_bar.xml
index 55e57ab..a204f17 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar.xml
@@ -35,18 +35,6 @@
             android:clipChildren="false"
             >
 
-            <ImageView android:id="@+id/clear_all_button"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:layout_alignParentRight="true"
-                android:layout_marginTop="1dp"
-                android:layout_marginRight="20dp"
-                android:paddingLeft="15dp"
-                android:paddingRight="15dp"
-                android:src="@drawable/ic_notify_clear"
-                android:visibility="invisible"
-                />
-
             <!-- notification icons & panel access -->
             <include layout="@layout/status_bar_notification_area" 
                 android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml
index 9f11e08..1641c70 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml
@@ -24,6 +24,18 @@
     android:gravity="right"
     >
 
+    <ImageView android:id="@+id/clear_all_button"
+        android:layout_width="wrap_content"
+        android:layout_height="@*android:dimen/status_bar_height"
+        android:layout_alignParentRight="true"
+        android:layout_alignParentBottom="true"
+        android:layout_marginRight="20dp"
+        android:paddingLeft="15dp"
+        android:paddingRight="15dp"
+        android:src="@drawable/ic_notify_clear"
+        android:visibility="invisible"
+        />
+
     <RelativeLayout
         android:id="@+id/content_parent"
         android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index d97b90f..1446099 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -135,4 +135,8 @@
     <skip />
     <!-- no translation found for gps_notification_found_text (4619274244146446464) -->
     <skip />
+
+    <!-- in Japanese the day of week should follow the date -->
+    <string name="status_bar_date_formatter">%2$s\n%1$s</string>
+
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 2b3118d..03b82fd 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -41,8 +41,9 @@
     <!-- Title shown in recents popup for inspecting an application's properties -->
     <string name="status_bar_recent_inspect_item_title">Inspect</string>
 
-
-
+    <!-- For formatting day of week and date in DateView.  Day of week precedes date by default,
+         but this may be overridden on a per-locale basis if necessary. -->
+    <string name="status_bar_date_formatter">%1$s\n%2$s</string>
 
     <!-- The label in the bar at the top of the status bar when there are no notifications
          showing.  [CHAR LIMIT=40]-->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 91a8855..ad236b7 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -52,4 +52,15 @@
         <item name="android:windowExitAnimation">@*android:anim/shrink_fade_out_from_bottom</item>
     </style>
 
+    <!-- Standard animations for hiding and showing the status bar. -->
+    <style name="Animation.StatusBar">
+        <item name="android:windowEnterAnimation">@anim/status_bar_enter</item>
+        <item name="android:windowExitAnimation">@anim/status_bar_exit</item>
+    </style>
+
+    <style name="Animation.StatusBar.IntruderAlert">
+        <item name="android:windowEnterAnimation">@anim/priority_alert_enter</item>
+        <item name="android:windowExitAnimation">@anim/priority_alert_exit</item>
+    </style>
+
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 7cc5ff7..e1231a5 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -93,9 +93,12 @@
             }
 
             super.onCreate(surfaceHolder);
-            IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
-            mReceiver = new WallpaperObserver();
-            registerReceiver(mReceiver, filter, null, mHandler);
+            
+            // Don't need this currently because the wallpaper service
+            // will restart the image wallpaper whenever the image changes.
+            //IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
+            //mReceiver = new WallpaperObserver();
+            //registerReceiver(mReceiver, filter, null, mHandler);
 
             updateSurfaceSize(surfaceHolder);
         }
@@ -103,7 +106,9 @@
         @Override
         public void onDestroy() {
             super.onDestroy();
-            unregisterReceiver(mReceiver);
+            if (mReceiver != null) {
+                unregisterReceiver(mReceiver);
+            }
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index c896046..d74b548 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -501,6 +501,7 @@
                     new RectF(mGlowBitmapPaddingLeftPx, mGlowBitmapPaddingTopPx,
                             outBitmap.getWidth() - mGlowBitmapPaddingRightPx,
                             outBitmap.getHeight() - mGlowBitmapPaddingBottomPx), paint);
+            canvas.setBitmap(null);
         }
         return outBitmap;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 3a47e6e..fc21929 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -294,6 +294,7 @@
             c.rotate(360f - degrees);
             c.translate(-dims[0] / 2, -dims[1] / 2);
             c.drawBitmap(mScreenBitmap, 0, 0, null);
+            c.setBitmap(null);
             mScreenBitmap = ss;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
index 918d5a3..61da1f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
@@ -119,7 +119,8 @@
                 PixelFormat.RGBX_8888);
         lp.gravity = getStatusBarGravity();
         lp.setTitle("StatusBar");
-        // TODO lp.windowAnimations = R.style.Animation_StatusBar;
+        lp.packageName = mContext.getPackageName();
+        lp.windowAnimations = R.style.Animation_StatusBar;
         WindowManagerImpl.getDefault().addView(sb, lp);
 
         if (SPEW) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
index 51fc7c2..3276e1f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
@@ -16,16 +16,9 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.animation.LayoutTransition;
 import android.content.Context;
 import android.util.AttributeSet;
-import android.view.Display;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.WindowManager;
 import android.widget.LinearLayout;
-import android.util.Slog;
-
 
 public class ExpandedView extends LinearLayout {
     PhoneStatusBar mService;
@@ -38,8 +31,6 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-
-        setLayerType(LAYER_TYPE_HARDWARE, null);
     }
 
     /** We want to shrink down to 0, and ignore the background. */
@@ -49,7 +40,7 @@
     }
 
     @Override
-     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
          super.onLayout(changed, left, top, right, bottom);
          int height = bottom - top;
          if (height != mPrevHeight) {
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 18026f1..7d1aedc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -16,12 +16,10 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.app.Service;
 import android.app.ActivityManagerNative;
 import android.app.Dialog;
 import android.app.Notification;
 import android.app.PendingIntent;
-import android.app.Service;
 import android.app.StatusBarManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -30,6 +28,7 @@
 import android.content.res.Resources;
 import android.content.res.Configuration;
 import android.graphics.PixelFormat;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
@@ -65,16 +64,12 @@
 import android.widget.RemoteViews;
 import android.widget.ScrollView;
 import android.widget.TextView;
-import android.widget.FrameLayout;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Set;
 
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.statusbar.StatusBarIconList;
 import com.android.internal.statusbar.StatusBarNotification;
 
 import com.android.systemui.R;
@@ -92,6 +87,9 @@
     static final boolean SPEW = false;
     public static final boolean DEBUG = false;
 
+    // additional instrumentation for testing purposes; intended to be left on during development
+    public static final boolean CHATTY = DEBUG || true;
+
     public static final String ACTION_STATUSBAR_START
             = "com.android.internal.policy.statusbar.START";
 
@@ -186,7 +184,6 @@
 
     boolean mAnimating;
     long mCurAnimationTime;
-    float mDisplayHeight;
     float mAnimY;
     float mAnimVel;
     float mAnimAccel;
@@ -201,6 +198,8 @@
     // tracking calls to View.setSystemUiVisibility()
     int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
 
+    final Point mDisplaySize = new Point();
+
     private class ExpandedDialog extends Dialog {
         ExpandedDialog(Context context) {
             super(context, com.android.internal.R.style.Theme_Light_NoTitleBar);
@@ -246,8 +245,11 @@
 
         Resources res = context.getResources();
 
+        mDisplay.getSize(mDisplaySize);
         loadDimens();
 
+        mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
+
         ExpandedView expanded = (ExpandedView)View.inflate(context,
                 R.layout.status_bar_expanded, null);
         expanded.mService = this;
@@ -506,7 +508,8 @@
         lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
         lp.y += height * 1.5; // FIXME
         lp.setTitle("IntruderAlert");
-        lp.windowAnimations = com.android.internal.R.style.Animation_StatusBar_IntruderAlert;
+        lp.packageName = mContext.getPackageName();
+        lp.windowAnimations = R.style.Animation_StatusBar_IntruderAlert;
 
         WindowManagerImpl.getDefault().addView(mIntruderAlertView, lp);
     }
@@ -1149,7 +1152,7 @@
         if (mAnimating) {
             y = (int)mAnimY;
         } else {
-            y = mDisplay.getHeight()-1;
+            y = mDisplaySize.y-1;
         }
         // Let the fling think that we're open so it goes in the right direction
         // and doesn't try to re-open the windowshade.
@@ -1205,7 +1208,7 @@
             if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
             incrementAnim();
             if (SPEW) Slog.d(TAG, "doAnimation after  mAnimY=" + mAnimY);
-            if (mAnimY >= mDisplay.getHeight()-1) {
+            if (mAnimY >= mDisplaySize.y-1) {
                 if (SPEW) Slog.d(TAG, "Animation completed to expanded state.");
                 mAnimating = false;
                 updateExpandedViewPos(EXPANDED_FULL_OPEN);
@@ -1261,6 +1264,10 @@
     }
 
     void prepareTracking(int y, boolean opening) {
+        if (CHATTY) {
+            Slog.d(TAG, "panel: beginning to track the user's touch, y=" + y + " opening=" + opening);
+        }
+
         mTracking = true;
         mVelocityTracker = VelocityTracker.obtain();
         if (opening) {
@@ -1290,8 +1297,11 @@
     }
 
     void performFling(int y, float vel, boolean always) {
+        if (CHATTY) {
+            Slog.d(TAG, "panel: will fling, y=" + y + " vel=" + vel);
+        }
+
         mAnimatingReveal = false;
-        mDisplayHeight = mDisplay.getHeight();
 
         mAnimY = y;
         mAnimVel = vel;
@@ -1301,7 +1311,7 @@
         if (mExpanded) {
             if (!always && (
                     vel > 200.0f
-                    || (y > (mDisplayHeight-25) && vel > -200.0f))) {
+                    || (y > (mDisplaySize.y-25) && vel > -200.0f))) {
                 // We are expanded, but they didn't move sufficiently to cause
                 // us to retract.  Animate back to the expanded position.
                 mAnimAccel = 2000.0f;
@@ -1319,7 +1329,7 @@
         } else {
             if (always || (
                     vel > 200.0f
-                    || (y > (mDisplayHeight/2) && vel > -200.0f))) {
+                    || (y > (mDisplaySize.y/2) && vel > -200.0f))) {
                 // We are collapsed, and they moved enough to allow us to
                 // expand.  Animate in the notifications.
                 mAnimAccel = 2000.0f;
@@ -1353,6 +1363,12 @@
         if (SPEW) {
             Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
                 + mDisabled);
+        } else if (CHATTY) {
+            if (event.getAction() == MotionEvent.ACTION_DOWN) {
+                Slog.d(TAG, String.format(
+                            "panel: ACTION_DOWN at (%f, %f) mDisabled=0x%08x",
+                            event.getRawX(), event.getRawY(), mDisabled));
+            }
         }
 
         if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
@@ -1371,14 +1387,14 @@
                 mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y;
             }
             if ((!mExpanded && y < hitSize) ||
-                    (mExpanded && y > (mDisplay.getHeight()-hitSize))) {
+                    (mExpanded && y > (mDisplaySize.y-hitSize))) {
 
                 // We drop events at the edge of the screen to make the windowshade come
                 // down by accident less, especially when pushing open a device with a keyboard
                 // that rotates (like g1 and droid)
                 int x = (int)event.getRawX();
                 final int edgeBorder = mEdgeBorder;
-                if (x >= edgeBorder && x < mDisplay.getWidth() - edgeBorder) {
+                if (x >= edgeBorder && x < mDisplaySize.x - edgeBorder) {
                     prepareTracking(y, !mExpanded);// opening if we're not already fully visible
                     mVelocityTracker.addMovement(event);
                 }
@@ -1626,10 +1642,9 @@
                     + ", mAnimAccel=" + mAnimAccel);
             pw.println("  mCurAnimationTime=" + mCurAnimationTime
                     + " mAnimLastTime=" + mAnimLastTime);
-            pw.println("  mDisplayHeight=" + mDisplayHeight
-                    + " mAnimatingReveal=" + mAnimatingReveal
+            pw.println("  mAnimatingReveal=" + mAnimatingReveal
                     + " mViewDelta=" + mViewDelta);
-            pw.println("  mDisplayHeight=" + mDisplayHeight);
+            pw.println("  mDisplaySize=" + mDisplaySize);
             pw.println("  mExpandedParams: " + mExpandedParams);
             pw.println("  mExpandedView: " + viewInfo(mExpandedView));
             pw.println("  mExpandedDialog: " + mExpandedDialog);
@@ -1721,17 +1736,13 @@
     void onTrackingViewAttached() {
         WindowManager.LayoutParams lp;
         int pixelFormat;
-        Drawable bg;
 
         /// ---------- Expanded View --------------
         pixelFormat = PixelFormat.TRANSLUCENT;
 
-        final int disph = mDisplay.getHeight();
         lp = mExpandedDialog.getWindow().getAttributes();
-        lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
-        lp.height = getExpandedHeight();
         lp.x = 0;
-        mTrackingPosition = lp.y = -disph; // sufficiently large negative
+        mTrackingPosition = lp.y = mDisplaySize.y; // sufficiently large negative
         lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
         lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
@@ -1741,9 +1752,9 @@
         lp.format = pixelFormat;
         lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
         lp.setTitle("StatusBarExpanded");
-        mExpandedDialog.getWindow().setAttributes(lp);
-        mExpandedDialog.getWindow().setFormat(pixelFormat);
         mExpandedParams = lp;
+        updateExpandedSize();
+        mExpandedDialog.getWindow().setFormat(pixelFormat);
 
         mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
         mExpandedDialog.setContentView(mExpandedView,
@@ -1751,7 +1762,6 @@
                                            ViewGroup.LayoutParams.MATCH_PARENT));
         mExpandedDialog.getWindow().setBackgroundDrawable(null);
         mExpandedDialog.show();
-        FrameLayout hack = (FrameLayout)mExpandedView.getParent();
     }
 
     void setDateViewVisibility(boolean visible, int anim) {
@@ -1768,6 +1778,20 @@
         }
     }
 
+    void updateExpandedInvisiblePosition() {
+        if (mTrackingView != null) {
+            mTrackingPosition = -mDisplaySize.y;
+            if (mTrackingParams != null) {
+                mTrackingParams.y = mTrackingPosition;
+                WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
+            }
+        }
+        if (mExpandedParams != null) {
+            mExpandedParams.y = -mDisplaySize.y;
+            mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+        }
+    }
+
     void updateExpandedViewPos(int expandedPosition) {
         if (SPEW) {
             Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition
@@ -1776,22 +1800,12 @@
         }
 
         int h = mStatusBarView.getHeight();
-        int disph = mDisplay.getHeight();
+        int disph = mDisplaySize.y;
 
         // If the expanded view is not visible, make sure they're still off screen.
         // Maybe the view was resized.
         if (!mExpandedVisible) {
-            if (mTrackingView != null) {
-                mTrackingPosition = -disph;
-                if (mTrackingParams != null) {
-                    mTrackingParams.y = mTrackingPosition;
-                    WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
-                }
-            }
-            if (mExpandedParams != null) {
-                mExpandedParams.y = -disph;
-                mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-            }
+            updateExpandedInvisiblePosition();
             return;
         }
 
@@ -1816,14 +1830,21 @@
         WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
 
         if (mExpandedParams != null) {
-            mCloseView.getLocationInWindow(mPositionTmp);
-            final int closePos = mPositionTmp[1];
+            if (mCloseView.getWindowVisibility() == View.VISIBLE) {
+                mCloseView.getLocationInWindow(mPositionTmp);
+                final int closePos = mPositionTmp[1];
 
-            mExpandedContents.getLocationInWindow(mPositionTmp);
-            final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();
+                mExpandedContents.getLocationInWindow(mPositionTmp);
+                final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();
 
-            mExpandedParams.y = pos + mTrackingView.getHeight()
-                    - (mTrackingParams.height-closePos) - contentsBottom;
+                mExpandedParams.y = pos + mTrackingView.getHeight()
+                        - (mTrackingParams.height-closePos) - contentsBottom;
+            } else {
+                // If the tracking view is not yet visible, then we can't have
+                // a good value of the close view location.  We need to wait for
+                // it to be visible to do a layout.
+                mExpandedParams.y = -mDisplaySize.y;
+            }
             int max = h;
             if (mExpandedParams.y > max) {
                 mExpandedParams.y = max;
@@ -1859,14 +1880,24 @@
         }
     }
 
-    int getExpandedHeight() {
-        return mDisplay.getHeight() - mStatusBarView.getHeight() - mCloseView.getHeight();
+    int getExpandedHeight(int disph) {
+        return disph - mStatusBarView.getHeight() - mCloseView.getHeight();
     }
 
-    void updateExpandedHeight() {
-        if (mExpandedView != null) {
-            mExpandedParams.height = getExpandedHeight();
-            mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+    void updateDisplaySize() {
+        mDisplay.getSize(mDisplaySize);
+        updateExpandedSize();
+    }
+
+    void updateExpandedSize() {
+        if (mExpandedDialog != null && mExpandedParams != null && mDisplaySize != null) {
+            mExpandedParams.width = mDisplaySize.x;
+            mExpandedParams.height = getExpandedHeight(mDisplaySize.y);
+            if (!mExpandedVisible) {
+                updateExpandedInvisiblePosition();
+            } else {
+                mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index c2390e8..db6907c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -77,6 +77,7 @@
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
+        mService.updateDisplaySize();
         boolean nightMode = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
                 == Configuration.UI_MODE_NIGHT_YES;
         if (mNightMode != nightMode) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java
index fd32a3d..fc0f332 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
+import android.os.Handler;
 import android.util.AttributeSet;
 import android.view.Display;
 import android.view.KeyEvent;
@@ -29,6 +30,7 @@
     PhoneStatusBar mService;
     boolean mTracking;
     int mStartX, mStartY;
+    Handler mHandler = new Handler();
 
     public TrackingView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -39,7 +41,6 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        mService.updateExpandedHeight();
     }
 
     @Override
@@ -60,4 +61,16 @@
         super.onAttachedToWindow();
         mService.onTrackingViewAttached();
     }
+
+    @Override
+    protected void onWindowVisibilityChanged(int visibility) {
+        super.onWindowVisibilityChanged(visibility);
+        if (visibility == VISIBLE) {
+            mHandler.post(new Runnable() {
+                @Override public void run() {
+                    mService.updateExpandedViewPos(PhoneStatusBar.EXPANDED_LEAVE_ALONE);
+                }
+            });
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
index 6ab03e1..a171514 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
@@ -28,6 +28,8 @@
 import android.view.View;
 import android.view.ViewParent;
 
+import com.android.systemui.R;
+
 import java.util.Date;
 
 public final class DateView extends TextView {
@@ -90,7 +92,7 @@
         Date now = new Date();
         CharSequence dow = DateFormat.format("EEEE", now);
         CharSequence date = DateFormat.getMediumDateFormat(getContext()).format(now);
-        setText(dow + "\n" + date);
+        setText(context.getString(R.string.status_bar_date_formatter, dow, date));
     }
 
     private boolean isVisible() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index f32c602..e675657 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -61,6 +61,7 @@
     // debug
     static final String TAG = "StatusBar.NetworkController";
     static final boolean DEBUG = false;
+    static final boolean CHATTY = true; // additional diagnostics, but not logspew
 
     // telephony
     boolean mHspaDataDistinguishable;
@@ -286,7 +287,7 @@
 
         @Override
         public void onDataConnectionStateChanged(int state, int networkType) {
-            if (DEBUG) {
+            if (DEBUG || CHATTY) {
                 Slog.d(TAG, "onDataConnectionStateChanged: state=" + state
                         + " type=" + networkType);
             }
@@ -521,6 +522,7 @@
                 }
             } else {
                 iconId = R.drawable.stat_sys_no_sim;
+                visible = false; // no SIM? no data
             }
         } else {
             // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
@@ -682,10 +684,19 @@
     // ===== Full or limited Internet connectivity ==================================
 
     private void updateConnectivity(Intent intent) {
+        if (CHATTY) {
+            Slog.d(TAG, "updateConnectivity: intent=" + intent);
+        }
+
         NetworkInfo info = (NetworkInfo)(intent.getParcelableExtra(
                 ConnectivityManager.EXTRA_NETWORK_INFO));
         int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
 
+        if (CHATTY) {
+            Slog.d(TAG, "updateConnectivity: networkInfo=" + info);
+            Slog.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus);
+        }
+
         int inetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
 
         switch (info.getType()) {
@@ -791,7 +802,12 @@
         }
 
         if (DEBUG) {
-            Slog.d(TAG, "refreshViews combinedSignalIconId=0x"
+            Slog.d(TAG, "refreshViews connected={"
+                    + (mWifiConnected?" wifi":"")
+                    + (mDataConnected?" data":"")
+                    + " } level="
+                    + ((mSignalStrength == null)?"??":Integer.toString(mSignalStrength.getLevel()))
+                    + " combinedSignalIconId=0x"
                     + Integer.toHexString(combinedSignalIconId)
                     + "/" + getResourceName(combinedSignalIconId)
                     + " dataDirectionOverlayIconId=0x" + Integer.toHexString(dataDirectionOverlayIconId)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
index 100ed55..fd58174 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
@@ -22,6 +22,7 @@
 import android.util.AttributeSet;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSubtype;
 import android.view.View;
 import android.widget.ImageView;
 
@@ -48,6 +49,9 @@
     private boolean mScreenLocked = false;
     private boolean mHardKeyboardAvailable;
 
+    // Please refer to InputMethodManagerService.TAG_TRY_SUPPRESSING_IME_SWITCHER
+    private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
+
     public InputMethodButton(Context context, AttributeSet attrs) {
         super(context, attrs);
 
@@ -64,10 +68,49 @@
         refreshStatusIcon();
     }
 
-    // Display IME switcher icon only when all of the followings are true:
-    // * There is only one enabled IME on the device.  (Note that the IME should be the system IME)
-    // * There are no explicitly enabled (by the user) subtypes of the IME, or the IME doesn't have
-    // its subtypes at all
+    // Refer to InputMethodManagerService.needsToShowImeSwitchOngoingNotification()
+    private boolean needsToShowIMEButtonWhenVisibilityAuto() {
+        List<InputMethodInfo> imis = mImm.getEnabledInputMethodList();
+        final int N = imis.size();
+        if (N > 2) return true;
+        if (N < 1) return false;
+        int nonAuxCount = 0;
+        int auxCount = 0;
+        InputMethodSubtype nonAuxSubtype = null;
+        InputMethodSubtype auxSubtype = null;
+        for(int i = 0; i < N; ++i) {
+            final InputMethodInfo imi = imis.get(i);
+            final List<InputMethodSubtype> subtypes = mImm.getEnabledInputMethodSubtypeList(
+                    imi, true);
+            final int subtypeCount = subtypes.size();
+            if (subtypeCount == 0) {
+                ++nonAuxCount;
+            } else {
+                for (int j = 0; j < subtypeCount; ++j) {
+                    final InputMethodSubtype subtype = subtypes.get(j);
+                    if (!subtype.isAuxiliary()) {
+                        ++nonAuxCount;
+                        nonAuxSubtype = subtype;
+                    } else {
+                        ++auxCount;
+                        auxSubtype = subtype;
+                    }
+                }
+            }
+        }
+        if (nonAuxCount > 1 || auxCount > 1) {
+            return true;
+        } else if (nonAuxCount == 1 && auxCount == 1) {
+            if (nonAuxSubtype != null && auxSubtype != null
+                    && nonAuxSubtype.getLocale().equals(auxSubtype.getLocale())
+                    && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) {
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
     private boolean needsToShowIMEButton() {
         if (!mShowButton || mScreenLocked) return false;
 
@@ -75,13 +118,10 @@
             return true;
         }
 
-        List<InputMethodInfo> imis = mImm.getEnabledInputMethodList();
-        final int size = imis.size();
         final int visibility = loadInputMethodSelectorVisibility();
         switch (visibility) {
             case ID_IME_BUTTON_VISIBILITY_AUTO:
-                return size > 1 || (size == 1
-                        && mImm.getEnabledInputMethodSubtypeList(imis.get(0), false).size() > 1);
+                return needsToShowIMEButtonWhenVisibilityAuto();
             case ID_IME_BUTTON_VISIBILITY_ALWAYS_SHOW:
                 return true;
             case ID_IME_BUTTON_VISIBILITY_ALWAYS_HIDE:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
index 74dbfef..d9cb4e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
@@ -40,6 +40,7 @@
     final static int PANEL_FADE_DURATION = 150;
 
     boolean mShowing;
+    boolean mHasClearableNotifications = false;
     int mNotificationCount = 0;
     NotificationPanelTitle mTitleArea;
     View mSettingsButton;
@@ -50,6 +51,7 @@
     View mSettingsView;
     ViewGroup mContentParent;
     TabletStatusBar mBar;
+    View mClearButton;
 
     // amount to slide mContentParent down by when mContentFrame is missing
     float mContentFrameMissingTranslation;
@@ -84,14 +86,27 @@
 
         mNotificationScroller = findViewById(R.id.notification_scroller);
         mContentFrame = (ViewGroup)findViewById(R.id.content_frame);
-        mContentFrameMissingTranslation =
-            mContentFrame.getBackground().getMinimumHeight() + 10;
+        mContentFrameMissingTranslation = 0; // not needed with current assets
+
+        // the "X" that appears in place of the clock when the panel is showing notifications
+        mClearButton = findViewById(R.id.clear_all_button);
+        mClearButton.setOnClickListener(mClearButtonListener);
 
         mShowing = false;
 
         setContentFrameVisible(mNotificationCount > 0, false);
     }
 
+    private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            mBar.clearAll();
+        }
+    };
+
+    public View getClearButton() {
+        return mClearButton;
+    }
+
     public void show(boolean show, boolean animate) {
         if (show && !mShowing) {
             setContentFrameVisible(mSettingsView != null || mNotificationCount > 0, false);
@@ -264,12 +279,16 @@
         if (mBar != null) {
             final boolean showX 
                 = (isShowing()
-                        && mNotificationScroller.getVisibility() == View.VISIBLE 
-                        && mNotificationCount > 0);
-            mBar.getClearButton().setVisibility(showX ? View.VISIBLE : View.INVISIBLE);
+                        && mHasClearableNotifications
+                        && mNotificationScroller.getVisibility() == View.VISIBLE);
+            getClearButton().setVisibility(showX ? View.VISIBLE : View.INVISIBLE);
         }
     }
 
+    public void setClearable(boolean clearable) {
+        mHasClearableNotifications = clearable;
+    }
+
     public void updatePanelModeButtons() {
         final boolean settingsVisible = (mSettingsView != null);
         mSettingsButton.setVisibility(!settingsVisible ? View.VISIBLE : View.INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index dc7e3137..7f56d45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -122,7 +122,6 @@
     View mNotificationTrigger;
     NotificationIconArea mNotificationIconArea;
     ViewGroup mNavigationArea;
-    View mClearButton;
 
     boolean mNotificationDNDMode;
     NotificationData.Entry mNotificationDNDDummyEntry;
@@ -453,10 +452,6 @@
         // the more notifications icon
         mNotificationIconArea = (NotificationIconArea)sb.findViewById(R.id.notificationIcons);
 
-        // the "X" that appears in place of the clock when the panel is showing notifications
-        mClearButton = sb.findViewById(R.id.clear_all_button);
-        mClearButton.setOnClickListener(mClearButtonListener);
-
         // where the icons go
         mIconLayout = (NotificationIconArea.IconLayout) sb.findViewById(R.id.icons);
         mIconLayout.setOnTouchListener(new NotificationIconTouchListener());
@@ -587,21 +582,6 @@
         return sb;
     }
 
-    private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
-        public void onClick(View v) {
-            try {
-                mBarService.onClearAllNotifications();
-            } catch (RemoteException ex) {
-                // system process is dead if we're here.
-            }
-            animateCollapse();
-        }
-    };
-
-    public View getClearButton() {
-        return mClearButton;
-    }
-
     public int getStatusBarHeight() {
         return mHeightReceiver.getHeight();
     }
@@ -1097,7 +1077,10 @@
 
         mCompatModeButton.refresh();
         if (mCompatModeButton.getVisibility() == View.VISIBLE) {
+            if (DEBUG_COMPAT_HELP
+                    || ! Prefs.read(mContext).getBoolean(Prefs.SHOWN_COMPAT_MODE_HELP, false)) {
                 showCompatibilityHelp();
+            }
         } else {
             hideCompatibilityHelp();
             mCompatModePanel.closePanel();
@@ -1204,6 +1187,9 @@
     }
 
     private void setAreThereNotifications() {
+        if (mNotificationPanel != null) {
+            mNotificationPanel.setClearable(mNotificationData.hasClearableItems());
+        }
     }
 
     /**
@@ -1606,6 +1592,10 @@
             }
 
             return;
+        } else if (0 != (mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) {
+            // if icons are disabled but we're not in DND mode, this is probably Setup and we should
+            // just leave the area totally empty
+            return;
         }
 
         int N = mNotificationData.size();
@@ -1775,6 +1765,15 @@
         return true;
     }
 
+    public void clearAll() {
+        try {
+            mBarService.onClearAllNotifications();
+        } catch (RemoteException ex) {
+            // system process is dead if we're here.
+        }
+        animateCollapse();
+    }
+
     public void userActivity() {
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
index dff1f6a..7d11251 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
@@ -94,6 +94,11 @@
         mHandler = h;
     }
 
+    /**
+     * Let the status bar know that if you tap on ignore while panel is showing, don't do anything.
+     * 
+     * Debounces taps on, say, a popup's trigger when the popup is already showing.
+     */
     public void setIgnoreChildren(int index, View ignore, View panel) {
         mIgnoreChildren[index] = ignore;
         mPanels[index] = panel;
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index bd5f739..8e062b7 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -5,7 +5,6 @@
     <application android:label="VpnDialogs"
             android:allowBackup="false" >
         <activity android:name=".ConfirmDialog"
-                android:permission="android.permission.VPN"
                 android:theme="@style/transparent">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index 40c0a02..d668e98 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -79,7 +79,7 @@
             mDataTransmitted = (TextView) view.findViewById(R.id.data_transmitted);
             mDataReceived = (TextView) view.findViewById(R.id.data_received);
 
-            if (mConfig.packagz.equals(VpnConfig.LEGACY_VPN)) {
+            if (mConfig.user.equals(VpnConfig.LEGACY_VPN)) {
                 mDialog = new AlertDialog.Builder(this)
                         .setIcon(android.R.drawable.ic_dialog_info)
                         .setTitle(R.string.legacy_title)
@@ -89,7 +89,7 @@
                         .create();
             } else {
                 PackageManager pm = getPackageManager();
-                ApplicationInfo app = pm.getApplicationInfo(mConfig.packagz, 0);
+                ApplicationInfo app = pm.getApplicationInfo(mConfig.user, 0);
                 mDialog = new AlertDialog.Builder(this)
                         .setIcon(app.loadIcon(pm))
                         .setTitle(app.loadLabel(pm))
@@ -131,7 +131,7 @@
             if (which == AlertDialog.BUTTON_POSITIVE) {
                 mConfig.configureIntent.send();
             } else if (which == AlertDialog.BUTTON_NEUTRAL) {
-                mService.prepareVpn(mConfig.packagz, VpnConfig.LEGACY_VPN);
+                mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN);
             }
         } catch (Exception e) {
             Log.e(TAG, "onClick", e);
diff --git a/policy/src/com/android/internal/policy/impl/IconUtilities.java b/policy/src/com/android/internal/policy/impl/IconUtilities.java
index 99055cf..4564f90 100644
--- a/policy/src/com/android/internal/policy/impl/IconUtilities.java
+++ b/policy/src/com/android/internal/policy/impl/IconUtilities.java
@@ -186,6 +186,7 @@
         mask.recycle();
 
         dest.drawBitmap(src, 0, 0, mPaint);
+        dest.setBitmap(null);
 
         return result;
     }
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
index 7a14480..afa92f1 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
@@ -232,10 +232,14 @@
      * @param resId resource id of the message
      */
     public void setCarrierHelpText(int resId) {
-        mCarrierHelpText = getContext().getText(resId);
+        mCarrierHelpText = getText(resId);
         update(CARRIER_HELP_TEXT, mCarrierHelpText);
     }
 
+    private CharSequence getText(int resId) {
+        return resId == 0 ? null : getContext().getText(resId);
+    }
+
     /**
      * Unlock help message.  This is typically for help with unlock widgets, e.g. "wrong password"
      * or "try again."
@@ -244,7 +248,7 @@
      * @param lockIcon
      */
     public void setHelpMessage(int textResId, int lockIcon) {
-        mHelpMessageText = getContext().getString(textResId);
+        mHelpMessageText = getText(textResId).toString();
         update(HELP_MESSAGE_TEXT, mHelpMessageText);
     }
 
@@ -262,7 +266,7 @@
                 case OWNER_INFO:
                 case CARRIER_TEXT:
                 default:
-                    Log.w(TAG, "Not showing message id " + what + ", str=" + string);
+                    if (DEBUG) Log.w(TAG, "Not showing message id " + what + ", str=" + string);
             }
         } else {
             updateStatusLines(mShowingStatus);
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
index 7faf1a4..77f1932 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
@@ -20,7 +20,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.res.Configuration;
 import android.database.ContentObserver;
 import static android.os.BatteryManager.BATTERY_STATUS_CHARGING;
 import static android.os.BatteryManager.BATTERY_STATUS_FULL;
@@ -29,7 +28,6 @@
 import android.os.BatteryManager;
 import android.os.Handler;
 import android.os.Message;
-import android.os.SystemClock;
 import android.provider.Settings;
 import android.provider.Telephony;
 import static android.provider.Telephony.Intents.EXTRA_PLMN;
@@ -503,7 +501,8 @@
         if (!mSimStateCallbacks.contains(callback)) {
             mSimStateCallbacks.add(callback);
         } else {
-            Log.e(TAG, "Object tried to add another SIM callback", new Exception("Whoops"));
+            if (DEBUG) Log.e(TAG, "Object tried to add another SIM callback",
+                    new Exception("Whoops"));
         }
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
index e5a7d64..6ee5861 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
@@ -127,10 +127,10 @@
         }
 
         if (enableScreenRotation) {
-            Log.d(TAG, "Rotation sensor for lock screen On!");
+            if (DEBUG) Log.d(TAG, "Rotation sensor for lock screen On!");
             mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR;
         } else {
-            Log.d(TAG, "Rotation sensor for lock screen Off!");
+            if (DEBUG) Log.d(TAG, "Rotation sensor for lock screen Off!");
             mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
         }
 
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index 47d34b3..ee6d2ee 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -646,7 +646,7 @@
      * @see #onWakeKeyWhenKeyguardShowingTq(int)
      */
     private void wakeWhenReadyLocked(int keyCode) {
-        if (true || DBG_WAKE) Log.d(TAG, "wakeWhenReadyLocked(" + keyCode + ")");
+        if (DBG_WAKE) Log.d(TAG, "wakeWhenReadyLocked(" + keyCode + ")");
 
         /**
          * acquire the handoff lock that will keep the cpu running.  this will
@@ -741,7 +741,7 @@
 
                 int sequence = intent.getIntExtra("seq", 0);
 
-                if (false) Log.d(TAG, "received DELAYED_KEYGUARD_ACTION with seq = "
+                if (DEBUG) Log.d(TAG, "received DELAYED_KEYGUARD_ACTION with seq = "
                         + sequence + ", mDelayedShowingSequence = " + mDelayedShowingSequence);
 
                 if (mDelayedShowingSequence == sequence) {
@@ -1033,13 +1033,15 @@
                         sfx.setStreamType(AudioManager.STREAM_SYSTEM);
                         sfx.play();
                     } else {
-                        Log.d(TAG, "playSounds: failed to load ringtone from uri: " + soundUri);
+                        if (DEBUG) Log.d(TAG, "playSounds: failed to load ringtone from uri: "
+                                + soundUri);
                     }
                 } else {
-                    Log.d(TAG, "playSounds: could not parse Uri: " + soundPath);
+                    if (DEBUG) Log.d(TAG, "playSounds: could not parse Uri: " + soundPath);
                 }
             } else {
-                Log.d(TAG, "playSounds: whichSound = " + whichSound + "; soundPath was null");
+                if (DEBUG) Log.d(TAG, "playSounds: whichSound = " + whichSound
+                        + "; soundPath was null");
             }
         }
     }
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 4a14dd9..9d360ac 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -23,7 +23,9 @@
 import com.android.internal.widget.multiwaveview.MultiWaveView;
 
 import android.app.ActivityManager;
+import android.content.ActivityNotFoundException;
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.view.KeyEvent;
@@ -181,14 +183,33 @@
             UnlockWidgetCommonMethods {
 
         private final MultiWaveView mMultiWaveView;
+        private boolean mCameraDisabled;
 
         MultiWaveViewMethods(MultiWaveView multiWaveView) {
             mMultiWaveView = multiWaveView;
+            final boolean cameraDisabled = mLockPatternUtils.getDevicePolicyManager()
+                    .getCameraDisabled(null);
+            if (cameraDisabled) {
+                Log.v(TAG, "Camera disabled by Device Policy");
+                mCameraDisabled = true;
+            } else {
+                // Camera is enabled if resource is initially defined for MultiWaveView
+                // in the lockscreen layout file
+                mCameraDisabled = mMultiWaveView.getTargetResourceId()
+                        != R.array.lockscreen_targets_with_camera;
+            }
         }
 
         public void updateResources() {
-            mMultiWaveView.setTargetResources(mSilentMode ? R.array.lockscreen_targets_when_silent
-                    : R.array.lockscreen_targets_when_soundon);
+            int resId;
+            if (mCameraDisabled) {
+                // Fall back to showing ring/silence if camera is disabled by DPM...
+                resId = mSilentMode ? R.array.lockscreen_targets_when_silent
+                    : R.array.lockscreen_targets_when_soundon;
+            } else {
+                resId = R.array.lockscreen_targets_with_camera;
+            }
+            mMultiWaveView.setTargetResources(resId);
         }
 
         public void onGrabbed(View v, int handle) {
@@ -200,12 +221,19 @@
         }
 
         public void onTrigger(View v, int target) {
-            if (target == 0) { // TODO: Use resources to determine which handle was used
+            if (target == 0 || target == 1) { // 0 = unlock/portrait, 1 = unlock/landscape
                 mCallback.goToUnlockScreen();
-            } else if (target == 2) {
-                toggleRingMode();
-                mUnlockWidgetMethods.updateResources();
-                mCallback.pokeWakelock();
+            } else if (target == 2 || target == 3) { // 2 = alt/portrait, 3 = alt/landscape
+                if (!mCameraDisabled) {
+                    // Broadcast an intent to start the Camera
+                    Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
+                    mContext.sendOrderedBroadcast(intent, null);
+                    mCallback.goToUnlockScreen();
+                } else {
+                    toggleRingMode();
+                    mUnlockWidgetMethods.updateResources();
+                    mCallback.pokeWakelock();
+                }
             }
         }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 174f733..6dd4948 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -35,13 +35,13 @@
 import com.android.internal.view.menu.MenuDialogHelper;
 import com.android.internal.view.menu.MenuPresenter;
 import com.android.internal.view.menu.MenuView;
-import com.android.internal.view.menu.SubMenuBuilder;
 import com.android.internal.widget.ActionBarContainer;
 import com.android.internal.widget.ActionBarContextView;
 import com.android.internal.widget.ActionBarView;
 
 import android.app.KeyguardManager;
 import android.content.Context;
+import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
@@ -51,8 +51,11 @@
 import android.media.AudioManager;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.AndroidRuntimeException;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
@@ -61,6 +64,8 @@
 import android.util.TypedValue;
 import android.view.ActionMode;
 import android.view.Gravity;
+import android.view.IRotationWatcher;
+import android.view.IWindowManager;
 import android.view.InputQueue;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
@@ -85,6 +90,9 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
 /**
  * Android-specific Window.
  * <p>
@@ -175,6 +183,15 @@
     private AudioManager mAudioManager;
     private KeyguardManager mKeyguardManager;
 
+    private int mUiOptions = 0;
+
+    static class WindowManagerHolder {
+        static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
+                ServiceManager.getService("window"));
+    }
+
+    static final RotationWatcher sRotationWatcher = new RotationWatcher();
+
     public PhoneWindow(Context context) {
         super(context);
         mLayoutInflater = LayoutInflater.from(context);
@@ -213,6 +230,11 @@
     }
 
     @Override
+    public void setUiOptions(int uiOptions) {
+        mUiOptions = uiOptions;
+    }
+
+    @Override
     public void setContentView(int layoutResID) {
         if (mContentParent == null) {
             installDecor();
@@ -408,8 +430,8 @@
                     if (st.iconMenuPresenter != null) {
                         st.iconMenuPresenter.saveHierarchyState(state);
                     }
-                    if (st.expandedMenuPresenter != null) {
-                        st.expandedMenuPresenter.saveHierarchyState(state);
+                    if (st.listMenuPresenter != null) {
+                        st.listMenuPresenter.saveHierarchyState(state);
                     }
 
                     // Remove the menu views since they need to be recreated
@@ -423,8 +445,8 @@
                     if (st.iconMenuPresenter != null) {
                         st.iconMenuPresenter.restoreHierarchyState(state);
                     }
-                    if (st.expandedMenuPresenter != null) {
-                        st.expandedMenuPresenter.restoreHierarchyState(state);
+                    if (st.listMenuPresenter != null) {
+                        st.listMenuPresenter.restoreHierarchyState(state);
                     }
 
                 } else {
@@ -545,6 +567,8 @@
             if (!st.shownPanelView.hasFocus()) {
                 st.shownPanelView.requestFocus();
             }
+        } else if (!st.isInListMode()) {
+            width = MATCH_PARENT;
         }
 
         st.isOpen = true;
@@ -558,7 +582,13 @@
                 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                 st.decorView.mDefaultOpacity);
 
-        lp.gravity = st.gravity;
+        if (st.isCompact) {
+            lp.gravity = getOptionsPanelGravity();
+            sRotationWatcher.addWindow(this);
+        } else {
+            lp.gravity = st.gravity;
+        }
+
         lp.windowAnimations = st.windowAnimations;
         
         wm.addView(st.decorView, lp);
@@ -601,6 +631,9 @@
             if (st.decorView != null) {
                 wm.removeView(st.decorView);
                 // Log.v(TAG, "Removing main menu from window manager.");
+                if (st.isCompact) {
+                    sRotationWatcher.removeWindow(this);
+                }
             }
 
             if (doCallback) {
@@ -952,6 +985,36 @@
     }
 
     /**
+     * Determine the gravity value for the options panel. This can
+     * differ in compact mode.
+     *
+     * @return gravity value to use for the panel window
+     */
+    private int getOptionsPanelGravity() {
+        try {
+            return WindowManagerHolder.sWindowManager.getPreferredOptionsPanelGravity();
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Couldn't getOptionsPanelGravity; using default", ex);
+            return Gravity.CENTER | Gravity.BOTTOM;
+        }
+    }
+
+    void onOptionsPanelRotationChanged() {
+        final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+        if (st == null) return;
+
+        final WindowManager.LayoutParams lp = st.decorView != null ?
+                (WindowManager.LayoutParams) st.decorView.getLayoutParams() : null;
+        if (lp != null) {
+            lp.gravity = getOptionsPanelGravity();
+            final ViewManager wm = getWindowManager();
+            if (wm != null) {
+                wm.updateViewLayout(st.decorView, lp);
+            }
+        }
+    }
+
+    /**
      * Initializes the panel associated with the panel feature state. You must
      * at the very least set PanelFeatureState.panel to the View implementing
      * its contents. The default implementation gets the panel from the menu.
@@ -973,8 +1036,8 @@
             mPanelMenuPresenterCallback = new PanelMenuPresenterCallback();
         }
 
-        MenuView menuView = st.isInExpandedMode
-                ? st.getExpandedMenuView(mPanelMenuPresenterCallback)
+        MenuView menuView = st.isInListMode()
+                ? st.getListMenuView(mPanelMenuPresenterCallback)
                 : st.getIconMenuView(mPanelMenuPresenterCallback);
 
         st.shownPanelView = (View) menuView;
@@ -2634,8 +2697,14 @@
                         mActionBar.initIndeterminateProgress();
                     }
 
-                    final boolean splitActionBar = getWindowStyle().getBoolean(
-                            com.android.internal.R.styleable.Window_windowSplitActionBar, false);
+                    boolean splitActionBar = false;
+                    if ((mUiOptions & ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW) != 0) {
+                        splitActionBar = getContext().getResources().getBoolean(
+                                com.android.internal.R.bool.split_action_bar_is_narrow);
+                    } else {
+                        splitActionBar = getWindowStyle().getBoolean(
+                                com.android.internal.R.styleable.Window_windowSplitActionBar, false);
+                    }
                     if (splitActionBar) {
                         final ActionBarContainer splitView = (ActionBarContainer) findViewById(
                                 com.android.internal.R.id.split_action_bar);
@@ -2648,7 +2717,7 @@
                                     com.android.internal.R.id.action_context_bar);
                             cab.setSplitView(splitView);
                         } else {
-                            Log.e(TAG, "Window style requested split action bar with " +
+                            Log.e(TAG, "Requested split action bar with " +
                                     "incompatible window decor! Ignoring request.");
                         }
                     }
@@ -3000,7 +3069,13 @@
         MenuBuilder menu;
 
         IconMenuPresenter iconMenuPresenter;
-        ListMenuPresenter expandedMenuPresenter;
+        ListMenuPresenter listMenuPresenter;
+
+        /** true if this menu will show in single-list compact mode */
+        boolean isCompact;
+
+        /** Theme resource ID for list elements of the panel menu */
+        int listPresenterTheme;
 
         /**
          * Whether the panel has been prepared (see
@@ -3050,11 +3125,15 @@
             refreshDecorView = false;
         }
 
+        public boolean isInListMode() {
+            return isInExpandedMode || isCompact;
+        }
+
         public boolean hasPanelItems() {
             if (shownPanelView == null) return false;
 
-            if (isInExpandedMode) {
-                return expandedMenuPresenter.getAdapter().getCount() > 0;
+            if (isCompact || isInExpandedMode) {
+                return listMenuPresenter.getAdapter().getCount() > 0;
             } else {
                 return ((ViewGroup) shownPanelView).getChildCount() > 0;
             }
@@ -3066,10 +3145,10 @@
         public void clearMenuPresenters() {
             if (menu != null) {
                 menu.removeMenuPresenter(iconMenuPresenter);
-                menu.removeMenuPresenter(expandedMenuPresenter);
+                menu.removeMenuPresenter(listMenuPresenter);
             }
             iconMenuPresenter = null;
-            expandedMenuPresenter = null;
+            listMenuPresenter = null;
         }
 
         void setStyle(Context context) {
@@ -3080,6 +3159,11 @@
                     com.android.internal.R.styleable.Theme_panelFullBackground, 0);
             windowAnimations = a.getResourceId(
                     com.android.internal.R.styleable.Theme_windowAnimationStyle, 0);
+            isCompact = a.getBoolean(
+                    com.android.internal.R.styleable.Theme_panelMenuIsCompact, false);
+            listPresenterTheme = a.getResourceId(
+                    com.android.internal.R.styleable.Theme_panelMenuListTheme,
+                    com.android.internal.R.style.Theme_ExpandedMenu);
             a.recycle();
         }
 
@@ -3087,22 +3171,26 @@
             this.menu = menu;
         }
 
-        MenuView getExpandedMenuView(MenuPresenter.Callback cb) {
+        MenuView getListMenuView(MenuPresenter.Callback cb) {
             if (menu == null) return null;
 
-            getIconMenuView(cb); // Need this initialized to know where our offset goes
-
-            if (expandedMenuPresenter == null) {
-                expandedMenuPresenter = new ListMenuPresenter(
-                        com.android.internal.R.layout.list_menu_item_layout,
-                        com.android.internal.R.style.Theme_ExpandedMenu);
-                expandedMenuPresenter.setCallback(cb);
-                expandedMenuPresenter.setId(com.android.internal.R.id.list_menu_presenter);
-                menu.addMenuPresenter(expandedMenuPresenter);
+            if (!isCompact) {
+                getIconMenuView(cb); // Need this initialized to know where our offset goes
             }
 
-            expandedMenuPresenter.setItemIndexOffset(iconMenuPresenter.getNumActualItemsShown());
-            MenuView result = expandedMenuPresenter.getMenuView(decorView);
+            if (listMenuPresenter == null) {
+                listMenuPresenter = new ListMenuPresenter(
+                        com.android.internal.R.layout.list_menu_item_layout, listPresenterTheme);
+                listMenuPresenter.setCallback(cb);
+                listMenuPresenter.setId(com.android.internal.R.id.list_menu_presenter);
+                menu.addMenuPresenter(listMenuPresenter);
+            }
+
+            if (iconMenuPresenter != null) {
+                listMenuPresenter.setItemIndexOffset(
+                        iconMenuPresenter.getNumActualItemsShown());
+            }
+            MenuView result = listMenuPresenter.getMenuView(decorView);
 
             return result;
         }
@@ -3209,6 +3297,69 @@
 
     }
 
+    static class RotationWatcher extends IRotationWatcher.Stub {
+        private Handler mHandler;
+        private final Runnable mRotationChanged = new Runnable() {
+            public void run() {
+                dispatchRotationChanged();
+            }
+        };
+        private final ArrayList<WeakReference<PhoneWindow>> mWindows =
+                new ArrayList<WeakReference<PhoneWindow>>();
+        private boolean mIsWatching;
+
+        @Override
+        public void onRotationChanged(int rotation) throws RemoteException {
+            mHandler.post(mRotationChanged);
+        }
+
+        public void addWindow(PhoneWindow phoneWindow) {
+            synchronized (mWindows) {
+                if (!mIsWatching) {
+                    try {
+                        WindowManagerHolder.sWindowManager.watchRotation(this);
+                        mHandler = new Handler();
+                        mIsWatching = true;
+                    } catch (RemoteException ex) {
+                        Log.e(TAG, "Couldn't start watching for device rotation", ex);
+                    }
+                }
+                mWindows.add(new WeakReference<PhoneWindow>(phoneWindow));
+            }
+        }
+
+        public void removeWindow(PhoneWindow phoneWindow) {
+            synchronized (mWindows) {
+                int i = 0;
+                while (i < mWindows.size()) {
+                    final WeakReference<PhoneWindow> ref = mWindows.get(i);
+                    final PhoneWindow win = ref.get();
+                    if (win == null || win == phoneWindow) {
+                        mWindows.remove(i);
+                    } else {
+                        i++;
+                    }
+                }
+            }
+        }
+
+        void dispatchRotationChanged() {
+            synchronized (mWindows) {
+                int i = 0;
+                while (i < mWindows.size()) {
+                    final WeakReference<PhoneWindow> ref = mWindows.get(i);
+                    final PhoneWindow win = ref.get();
+                    if (win != null) {
+                        win.onOptionsPanelRotationChanged();
+                        i++;
+                    } else {
+                        mWindows.remove(i);
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * Simple implementation of MenuBuilder.Callback that:
      * <li> Opens a submenu when selected.
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index b7f6adf..a2dbb78 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -113,6 +113,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
@@ -162,36 +163,39 @@
     static final int APPLICATION_LAYER = 2;
     static final int PHONE_LAYER = 3;
     static final int SEARCH_BAR_LAYER = 4;
-    static final int STATUS_BAR_SUB_PANEL_LAYER = 5;
-    static final int SYSTEM_DIALOG_LAYER = 6;
+    static final int SYSTEM_DIALOG_LAYER = 5;
     // toasts and the plugged-in battery thing
-    static final int TOAST_LAYER = 7;
+    static final int TOAST_LAYER = 6;
     // SIM errors and unlock.  Not sure if this really should be in a high layer.
-    static final int PRIORITY_PHONE_LAYER = 8;
+    static final int PRIORITY_PHONE_LAYER = 7;
     // like the ANR / app crashed dialogs
-    static final int SYSTEM_ALERT_LAYER = 9;
+    static final int SYSTEM_ALERT_LAYER = 8;
     // system-level error dialogs
-    static final int SYSTEM_ERROR_LAYER = 10;
+    static final int SYSTEM_ERROR_LAYER = 9;
     // on-screen keyboards and other such input method user interfaces go here.
-    static final int INPUT_METHOD_LAYER = 11;
+    static final int INPUT_METHOD_LAYER = 10;
     // on-screen keyboards and other such input method user interfaces go here.
-    static final int INPUT_METHOD_DIALOG_LAYER = 12;
+    static final int INPUT_METHOD_DIALOG_LAYER = 11;
     // the keyguard; nothing on top of these can take focus, since they are
     // responsible for power management when displayed.
-    static final int KEYGUARD_LAYER = 13;
-    static final int KEYGUARD_DIALOG_LAYER = 14;
+    static final int KEYGUARD_LAYER = 12;
+    static final int KEYGUARD_DIALOG_LAYER = 13;
+    static final int STATUS_BAR_SUB_PANEL_LAYER = 14;
     static final int STATUS_BAR_LAYER = 15;
     static final int STATUS_BAR_PANEL_LAYER = 16;
     // the navigation bar, if available, shows atop most things
     static final int NAVIGATION_BAR_LAYER = 17;
+    // the on-screen volume indicator and controller shown when the user
+    // changes the device volume
+    static final int VOLUME_OVERLAY_LAYER = 18;
     // the drag layer: input for drag-and-drop is associated with this window,
     // which sits above all other focusable windows
-    static final int DRAG_LAYER = 18;
+    static final int DRAG_LAYER = 19;
     // things in here CAN NOT take focus, but are shown on top of everything else.
-    static final int SYSTEM_OVERLAY_LAYER = 19;
-    static final int SECURE_SYSTEM_OVERLAY_LAYER = 20;
+    static final int SYSTEM_OVERLAY_LAYER = 20;
+    static final int SECURE_SYSTEM_OVERLAY_LAYER = 21;
     // the (mouse) pointer layer
-    static final int POINTER_LAYER = 21;
+    static final int POINTER_LAYER = 22;
 
     static final int APPLICATION_MEDIA_SUBLAYER = -2;
     static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
@@ -1057,6 +1061,8 @@
             return INPUT_METHOD_LAYER;
         case TYPE_INPUT_METHOD_DIALOG:
             return INPUT_METHOD_DIALOG_LAYER;
+        case TYPE_VOLUME_OVERLAY:
+            return VOLUME_OVERLAY_LAYER;
         case TYPE_SYSTEM_OVERLAY:
             return SYSTEM_OVERLAY_LAYER;
         case TYPE_SECURE_SYSTEM_OVERLAY:
@@ -3012,7 +3018,8 @@
         }
     }
 
-    Runnable mScreenSaverActivator = new Runnable() {
+    Runnable mScreenSaverActivator = null;
+    /*new Runnable() {
         public void run() {
             synchronized (this) {
                 if (!(mScreenSaverEnabled && mScreenOn)) {
@@ -3043,9 +3050,12 @@
             }
         }
     };
+    */
 
     // Must call while holding mLock
     private void updateScreenSaverTimeoutLocked() {
+        if (mScreenSaverActivator == null) return;
+
         synchronized (mScreenSaverActivator) {
             mHandler.removeCallbacks(mScreenSaverActivator);
             if (mScreenSaverEnabled && mScreenOn && mScreenSaverTimeout > 0) {
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index b11ec63..e201b17 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -51,6 +51,8 @@
 
 #include <media/EffectsFactoryApi.h>
 #include <audio_effects/effect_visualizer.h>
+#include <audio_effects/effect_ns.h>
+#include <audio_effects/effect_aec.h>
 
 #include <cpustats/ThreadCpuUsage.h>
 #include <powermanager/PowerManager.h>
@@ -148,7 +150,8 @@
 
 AudioFlinger::AudioFlinger()
     : BnAudioFlinger(),
-        mPrimaryHardwareDev(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1)
+        mPrimaryHardwareDev(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1),
+        mBtNrec(false)
 {
 }
 
@@ -717,6 +720,31 @@
             final_result = result ?: final_result;
         }
         mHardwareStatus = AUDIO_HW_IDLE;
+        // disable AEC and NS if the device is a BT SCO headset supporting those pre processings
+        AudioParameter param = AudioParameter(keyValuePairs);
+        String8 value;
+        if (param.get(String8(AUDIO_PARAMETER_KEY_BT_NREC), value) == NO_ERROR) {
+            Mutex::Autolock _l(mLock);
+            bool btNrec = (value == AUDIO_PARAMETER_VALUE_ON);
+            if (mBtNrec != btNrec) {
+                for (size_t i = 0; i < mRecordThreads.size(); i++) {
+                    sp<RecordThread> thread = mRecordThreads.valueAt(i);
+                    RecordThread::RecordTrack *track = thread->track();
+                    if (track != NULL) {
+                        audio_devices_t device = (audio_devices_t)(
+                                thread->device() & AUDIO_DEVICE_IN_ALL);
+                        bool suspend = audio_is_bluetooth_sco_device(device) && btNrec;
+                        thread->setEffectSuspended(FX_IID_AEC,
+                                                   suspend,
+                                                   track->sessionId());
+                        thread->setEffectSuspended(FX_IID_NS,
+                                                   suspend,
+                                                   track->sessionId());
+                    }
+                }
+                mBtNrec = btNrec;
+            }
+        }
         return final_result;
     }
 
@@ -1130,6 +1158,140 @@
     LOGW("power manager service died !!!");
 }
 
+void AudioFlinger::ThreadBase::setEffectSuspended(
+        const effect_uuid_t *type, bool suspend, int sessionId)
+{
+    Mutex::Autolock _l(mLock);
+    setEffectSuspended_l(type, suspend, sessionId);
+}
+
+void AudioFlinger::ThreadBase::setEffectSuspended_l(
+        const effect_uuid_t *type, bool suspend, int sessionId)
+{
+    sp<EffectChain> chain;
+    chain = getEffectChain_l(sessionId);
+    if (chain != 0) {
+        if (type != NULL) {
+            chain->setEffectSuspended_l(type, suspend);
+        } else {
+            chain->setEffectSuspendedAll_l(suspend);
+        }
+    }
+
+    updateSuspendedSessions_l(type, suspend, sessionId);
+}
+
+void AudioFlinger::ThreadBase::checkSuspendOnAddEffectChain_l(const sp<EffectChain>& chain)
+{
+    int index = mSuspendedSessions.indexOfKey(chain->sessionId());
+    if (index < 0) {
+        return;
+    }
+
+    KeyedVector <int, sp<SuspendedSessionDesc> > sessionEffects =
+            mSuspendedSessions.editValueAt(index);
+
+    for (size_t i = 0; i < sessionEffects.size(); i++) {
+        sp <SuspendedSessionDesc> desc = sessionEffects.valueAt(i);
+        for (int j = 0; j < desc->mRefCount; j++) {
+            if (sessionEffects.keyAt(i) == EffectChain::kKeyForSuspendAll) {
+                chain->setEffectSuspendedAll_l(true);
+            } else {
+                LOGV("checkSuspendOnAddEffectChain_l() suspending effects %08x",
+                     desc->mType.timeLow);
+                chain->setEffectSuspended_l(&desc->mType, true);
+            }
+        }
+    }
+}
+
+void AudioFlinger::ThreadBase::updateSuspendedSessionsOnRemoveEffectChain_l(
+        const sp<EffectChain>& chain)
+{
+    int index = mSuspendedSessions.indexOfKey(chain->sessionId());
+    if (index < 0) {
+        return;
+    }
+    LOGV("updateSuspendedSessionsOnRemoveEffectChain_l() removed suspended session %d",
+         chain->sessionId());
+    mSuspendedSessions.removeItemsAt(index);
+}
+
+void AudioFlinger::ThreadBase::updateSuspendedSessions_l(const effect_uuid_t *type,
+                                                         bool suspend,
+                                                         int sessionId)
+{
+    int index = mSuspendedSessions.indexOfKey(sessionId);
+
+    KeyedVector <int, sp<SuspendedSessionDesc> > sessionEffects;
+
+    if (suspend) {
+        if (index >= 0) {
+            sessionEffects = mSuspendedSessions.editValueAt(index);
+        } else {
+            mSuspendedSessions.add(sessionId, sessionEffects);
+        }
+    } else {
+        if (index < 0) {
+            return;
+        }
+        sessionEffects = mSuspendedSessions.editValueAt(index);
+    }
+
+
+    int key = EffectChain::kKeyForSuspendAll;
+    if (type != NULL) {
+        key = type->timeLow;
+    }
+    index = sessionEffects.indexOfKey(key);
+
+    sp <SuspendedSessionDesc> desc;
+    if (suspend) {
+        if (index >= 0) {
+            desc = sessionEffects.valueAt(index);
+        } else {
+            desc = new SuspendedSessionDesc();
+            if (type != NULL) {
+                memcpy(&desc->mType, type, sizeof(effect_uuid_t));
+            }
+            sessionEffects.add(key, desc);
+            LOGV("updateSuspendedSessions_l() suspend adding effect %08x", key);
+        }
+        desc->mRefCount++;
+    } else {
+        if (index < 0) {
+            return;
+        }
+        desc = sessionEffects.valueAt(index);
+        if (--desc->mRefCount == 0) {
+            LOGV("updateSuspendedSessions_l() restore removing effect %08x", key);
+            sessionEffects.removeItemsAt(index);
+            if (sessionEffects.isEmpty()) {
+                LOGV("updateSuspendedSessions_l() restore removing session %d",
+                                 sessionId);
+                mSuspendedSessions.removeItem(sessionId);
+            }
+        }
+    }
+    if (!sessionEffects.isEmpty()) {
+        mSuspendedSessions.replaceValueFor(sessionId, sessionEffects);
+    }
+}
+
+void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
+                                                            bool enabled,
+                                                            int sessionId)
+{
+    Mutex::Autolock _l(mLock);
+
+    // TODO: implement PlaybackThread or RecordThread specific behavior here
+
+    sp<EffectChain> chain = getEffectChain_l(sessionId);
+    if (chain != 0) {
+        chain->checkSuspendOnEffectEnabled(effect, enabled);
+    }
+}
+
 // ----------------------------------------------------------------------------
 
 AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger,
@@ -4180,7 +4342,11 @@
         }
 
         mTrack = track.get();
-
+        // disable AEC and NS if the device is a BT SCO headset supporting those pre processings
+        bool suspend = audio_is_bluetooth_sco_device(
+                (audio_devices_t)(mDevice & AUDIO_DEVICE_IN_ALL)) && mAudioFlinger->btNrec();
+        setEffectSuspended_l(FX_IID_AEC, suspend, sessionId);
+        setEffectSuspended_l(FX_IID_NS, suspend, sessionId);
     }
     lStatus = NO_ERROR;
 
@@ -4400,6 +4566,13 @@
                 status = BAD_VALUE;
             } else {
                 mDevice &= (uint32_t)~(value & AUDIO_DEVICE_IN_ALL);
+                // disable AEC and NS if the device is a BT SCO headset supporting those pre processings
+                if (mTrack != NULL) {
+                    bool suspend = audio_is_bluetooth_sco_device(
+                            (audio_devices_t)value) && mAudioFlinger->btNrec();
+                    setEffectSuspended_l(FX_IID_AEC, suspend, mTrack->sessionId());
+                    setEffectSuspended_l(FX_IID_NS, suspend, mTrack->sessionId());
+                }
             }
             mDevice |= (uint32_t)value;
         }
@@ -4537,6 +4710,12 @@
     return result;
 }
 
+AudioFlinger::RecordThread::RecordTrack* AudioFlinger::RecordThread::track()
+{
+    Mutex::Autolock _l(mLock);
+    return mTrack;
+}
+
 AudioFlinger::AudioStreamIn* AudioFlinger::RecordThread::getInput()
 {
     Mutex::Autolock _l(mLock);
@@ -4948,10 +5127,6 @@
 }
 
 
-// this UUID must match the one defined in media/libeffects/EffectVisualizer.cpp
-static const effect_uuid_t VISUALIZATION_UUID_ =
-    {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
-
 sp<IEffect> AudioFlinger::createEffect(pid_t pid,
         effect_descriptor_t *pDesc,
         const sp<IEffectClient>& effectClient,
@@ -4989,14 +5164,6 @@
         goto Exit;
     }
 
-    // check recording permission for visualizer
-    if ((memcmp(&pDesc->type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0 ||
-         memcmp(&pDesc->uuid, &VISUALIZATION_UUID_, sizeof(effect_uuid_t)) == 0) &&
-        !recordingAllowed()) {
-        lStatus = PERMISSION_DENIED;
-        goto Exit;
-    }
-
     if (io == 0) {
         if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
             // output must be specified by AudioPolicyManager when using session
@@ -5077,6 +5244,13 @@
             goto Exit;
         }
 
+        // check recording permission for visualizer
+        if ((memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) &&
+            !recordingAllowed()) {
+            lStatus = PERMISSION_DENIED;
+            goto Exit;
+        }
+
         // return effect descriptor
         memcpy(pDesc, &desc, sizeof(effect_descriptor_t));
 
@@ -5143,10 +5317,10 @@
     return handle;
 }
 
-status_t AudioFlinger::moveEffects(int session, int srcOutput, int dstOutput)
+status_t AudioFlinger::moveEffects(int sessionId, int srcOutput, int dstOutput)
 {
     LOGV("moveEffects() session %d, srcOutput %d, dstOutput %d",
-            session, srcOutput, dstOutput);
+            sessionId, srcOutput, dstOutput);
     Mutex::Autolock _l(mLock);
     if (srcOutput == dstOutput) {
         LOGW("moveEffects() same dst and src outputs %d", dstOutput);
@@ -5165,24 +5339,24 @@
 
     Mutex::Autolock _dl(dstThread->mLock);
     Mutex::Autolock _sl(srcThread->mLock);
-    moveEffectChain_l(session, srcThread, dstThread, false);
+    moveEffectChain_l(sessionId, srcThread, dstThread, false);
 
     return NO_ERROR;
 }
 
 // moveEffectChain_l mustbe called with both srcThread and dstThread mLocks held
-status_t AudioFlinger::moveEffectChain_l(int session,
+status_t AudioFlinger::moveEffectChain_l(int sessionId,
                                    AudioFlinger::PlaybackThread *srcThread,
                                    AudioFlinger::PlaybackThread *dstThread,
                                    bool reRegister)
 {
     LOGV("moveEffectChain_l() session %d from thread %p to thread %p",
-            session, srcThread, dstThread);
+            sessionId, srcThread, dstThread);
 
-    sp<EffectChain> chain = srcThread->getEffectChain_l(session);
+    sp<EffectChain> chain = srcThread->getEffectChain_l(sessionId);
     if (chain == 0) {
         LOGW("moveEffectChain_l() effect chain for session %d not on source thread %p",
-                session, srcThread);
+                sessionId, srcThread);
         return INVALID_OPERATION;
     }
 
@@ -5217,7 +5391,7 @@
             AudioSystem::registerEffect(&effect->desc(),
                                         dstOutput,
                                         strategy,
-                                        session,
+                                        sessionId,
                                         effect->id());
         }
         effect = chain->getEffectFromId_l(0);
@@ -5459,6 +5633,7 @@
 
 void AudioFlinger::ThreadBase::disconnectEffect(const sp<EffectModule>& effect,
                                                     const wp<EffectHandle>& handle) {
+
     Mutex::Autolock _l(mLock);
     LOGV("disconnectEffect() %p effect %p", this, effect.get());
     // delete the effect module if removing last handle on it
@@ -5525,6 +5700,7 @@
         if (mEffectChains[i]->sessionId() < session) break;
     }
     mEffectChains.insertAt(chain, i);
+    checkSuspendOnAddEffectChain_l(chain);
 
     return NO_ERROR;
 }
@@ -5537,6 +5713,7 @@
 
     for (size_t i = 0; i < mEffectChains.size(); i++) {
         if (chain == mEffectChains[i]) {
+            updateSuspendedSessionsOnRemoveEffectChain_l(chain);
             mEffectChains.removeAt(i);
             // detach all active tracks from the chain
             for (size_t i = 0 ; i < mActiveTracks.size() ; ++i) {
@@ -5614,6 +5791,8 @@
     chain->setInBuffer(NULL);
     chain->setOutBuffer(NULL);
 
+    checkSuspendOnAddEffectChain_l(chain);
+
     mEffectChains.add(chain);
 
     return NO_ERROR;
@@ -5626,6 +5805,7 @@
             "removeEffectChain_l() %p invalid chain size %d on thread %p",
             chain.get(), mEffectChains.size(), this);
     if (mEffectChains.size() == 1) {
+        updateSuspendedSessionsOnRemoveEffectChain_l(chain);
         mEffectChains.removeAt(0);
     }
     return 0;
@@ -5644,7 +5824,7 @@
                                         int id,
                                         int sessionId)
     : mThread(wThread), mChain(chain), mId(id), mSessionId(sessionId), mEffectInterface(NULL),
-      mStatus(NO_INIT), mState(IDLE)
+      mStatus(NO_INIT), mState(IDLE), mSuspended(false)
 {
     LOGV("Constructor %p", this);
     int lStatus;
@@ -5711,14 +5891,17 @@
     }
     // if inserted in first place, move effect control from previous owner to this handle
     if (i == 0) {
+        bool enabled = false;
         if (h != 0) {
-            h->setControl(false, true);
+            enabled = h->enabled();
+            h->setControl(false/*hasControl*/, true /*signal*/, enabled /*enabled*/);
         }
-        handle->setControl(true, false);
+        handle->setControl(true /*hasControl*/, false /*signal*/, enabled /*enabled*/);
         status = NO_ERROR;
     } else {
         status = ALREADY_EXISTS;
     }
+    LOGV("addHandle() %p added handle %p in position %d", this, handle.get(), i);
     mHandles.insertAt(handle, i);
     return status;
 }
@@ -5734,13 +5917,21 @@
     if (i == size) {
         return size;
     }
+    LOGV("removeHandle() %p removed handle %p in position %d", this, handle.unsafe_get(), i);
+
+    bool enabled = false;
+    EffectHandle *hdl = handle.unsafe_get();
+    if (hdl) {
+        LOGV("removeHandle() unsafe_get OK");
+        enabled = hdl->enabled();
+    }
     mHandles.removeAt(i);
     size = mHandles.size();
     // if removed from first place, move effect control from this handle to next in line
     if (i == 0 && size != 0) {
         sp<EffectHandle> h = mHandles[0].promote();
         if (h != 0) {
-            h->setControl(true, true);
+            h->setControl(true /*hasControl*/, true /*signal*/ , enabled /*enabled*/);
         }
     }
 
@@ -5754,8 +5945,21 @@
     return size;
 }
 
+sp<AudioFlinger::EffectHandle> AudioFlinger::EffectModule::controlHandle()
+{
+    Mutex::Autolock _l(mLock);
+    sp<EffectHandle> handle;
+    if (mHandles.size() != 0) {
+        handle = mHandles[0].promote();
+    }
+    return handle;
+}
+
+
+
 void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle)
 {
+    LOGV("disconnect() %p handle %p ", this, handle.unsafe_get());
     // keep a strong reference on this EffectModule to avoid calling the
     // destructor before we exit
     sp<EffectModule> keep(this);
@@ -6222,6 +6426,17 @@
     return status;
 }
 
+void AudioFlinger::EffectModule::setSuspended(bool suspended)
+{
+    Mutex::Autolock _l(mLock);
+    mSuspended = suspended;
+}
+bool AudioFlinger::EffectModule::suspended()
+{
+    Mutex::Autolock _l(mLock);
+    return mSuspended;
+}
+
 status_t AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
@@ -6318,7 +6533,8 @@
                                         const sp<IEffectClient>& effectClient,
                                         int32_t priority)
     : BnEffect(),
-    mEffect(effect), mEffectClient(effectClient), mClient(client), mPriority(priority), mHasControl(false)
+    mEffect(effect), mEffectClient(effectClient), mClient(client),
+    mPriority(priority), mHasControl(false), mEnabled(false)
 {
     LOGV("constructor %p", this);
 
@@ -6341,30 +6557,66 @@
 {
     LOGV("Destructor %p", this);
     disconnect();
+    LOGV("Destructor DONE %p", this);
 }
 
 status_t AudioFlinger::EffectHandle::enable()
 {
+    LOGV("enable %p", this);
     if (!mHasControl) return INVALID_OPERATION;
     if (mEffect == 0) return DEAD_OBJECT;
 
+    mEnabled = true;
+
+    sp<ThreadBase> thread = mEffect->thread().promote();
+    if (thread != 0) {
+        thread->checkSuspendOnEffectEnabled(mEffect, true, mEffect->sessionId());
+    }
+
+    // checkSuspendOnEffectEnabled() can suspend this same effect when enabled
+    if (mEffect->suspended()) {
+        return NO_ERROR;
+    }
+
     return mEffect->setEnabled(true);
 }
 
 status_t AudioFlinger::EffectHandle::disable()
 {
+    LOGV("disable %p", this);
     if (!mHasControl) return INVALID_OPERATION;
-    if (mEffect == NULL) return DEAD_OBJECT;
+    if (mEffect == 0) return DEAD_OBJECT;
 
-    return mEffect->setEnabled(false);
+    mEnabled = false;
+
+    if (mEffect->suspended()) {
+        return NO_ERROR;
+    }
+
+    status_t status = mEffect->setEnabled(false);
+
+    sp<ThreadBase> thread = mEffect->thread().promote();
+    if (thread != 0) {
+        thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId());
+    }
+
+    return status;
 }
 
 void AudioFlinger::EffectHandle::disconnect()
 {
+    LOGV("disconnect %p", this);
     if (mEffect == 0) {
         return;
     }
+
     mEffect->disconnect(this);
+
+    sp<ThreadBase> thread = mEffect->thread().promote();
+    if (thread != 0) {
+        thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId());
+    }
+
     // release sp on module => module destructor can be called now
     mEffect.clear();
     if (mCblk) {
@@ -6456,11 +6708,13 @@
     return mCblkMemory;
 }
 
-void AudioFlinger::EffectHandle::setControl(bool hasControl, bool signal)
+void AudioFlinger::EffectHandle::setControl(bool hasControl, bool signal, bool enabled)
 {
     LOGV("setControl %p control %d", this, hasControl);
 
     mHasControl = hasControl;
+    mEnabled = enabled;
+
     if (signal && mEffectClient != 0) {
         mEffectClient->controlStatusChanged(hasControl);
     }
@@ -6531,7 +6785,7 @@
 
 }
 
-// getEffectFromDesc_l() must be called with PlaybackThread::mLock held
+// getEffectFromDesc_l() must be called with ThreadBase::mLock held
 sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromDesc_l(effect_descriptor_t *descriptor)
 {
     sp<EffectModule> effect;
@@ -6546,7 +6800,7 @@
     return effect;
 }
 
-// getEffectFromId_l() must be called with PlaybackThread::mLock held
+// getEffectFromId_l() must be called with ThreadBase::mLock held
 sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId_l(int id)
 {
     sp<EffectModule> effect;
@@ -6562,6 +6816,22 @@
     return effect;
 }
 
+// getEffectFromType_l() must be called with ThreadBase::mLock held
+sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromType_l(
+        const effect_uuid_t *type)
+{
+    sp<EffectModule> effect;
+    size_t size = mEffects.size();
+
+    for (size_t i = 0; i < size; i++) {
+        if (memcmp(&mEffects[i]->desc().type, type, sizeof(effect_uuid_t)) == 0) {
+            effect = mEffects[i];
+            break;
+        }
+    }
+    return effect;
+}
+
 // Must be called with EffectChain::mLock locked
 void AudioFlinger::EffectChain::process_l()
 {
@@ -6856,6 +7126,166 @@
     return NO_ERROR;
 }
 
+// must be called with ThreadBase::mLock held
+void AudioFlinger::EffectChain::setEffectSuspended_l(
+        const effect_uuid_t *type, bool suspend)
+{
+    sp<SuspendedEffectDesc> desc;
+    // use effect type UUID timelow as key as there is no real risk of identical
+    // timeLow fields among effect type UUIDs.
+    int index = mSuspendedEffects.indexOfKey(type->timeLow);
+    if (suspend) {
+        if (index >= 0) {
+            desc = mSuspendedEffects.valueAt(index);
+        } else {
+            desc = new SuspendedEffectDesc();
+            memcpy(&desc->mType, type, sizeof(effect_uuid_t));
+            mSuspendedEffects.add(type->timeLow, desc);
+            LOGV("setEffectSuspended_l() add entry for %08x", type->timeLow);
+        }
+        if (desc->mRefCount++ == 0) {
+            sp<EffectModule> effect = getEffectIfEnabled(type);
+            if (effect != 0) {
+                desc->mEffect = effect;
+                effect->setSuspended(true);
+                effect->setEnabled(false);
+            }
+        }
+    } else {
+        if (index < 0) {
+            return;
+        }
+        desc = mSuspendedEffects.valueAt(index);
+        if (desc->mRefCount <= 0) {
+            LOGW("setEffectSuspended_l() restore refcount should not be 0 %d", desc->mRefCount);
+            desc->mRefCount = 1;
+        }
+        if (--desc->mRefCount == 0) {
+            LOGV("setEffectSuspended_l() remove entry for %08x", mSuspendedEffects.keyAt(index));
+            if (desc->mEffect != 0) {
+                sp<EffectModule> effect = desc->mEffect.promote();
+                if (effect != 0) {
+                    effect->setSuspended(false);
+                    sp<EffectHandle> handle = effect->controlHandle();
+                    if (handle != 0) {
+                        effect->setEnabled(handle->enabled());
+                    }
+                }
+                desc->mEffect.clear();
+            }
+            mSuspendedEffects.removeItemsAt(index);
+        }
+    }
+}
+
+// must be called with ThreadBase::mLock held
+void AudioFlinger::EffectChain::setEffectSuspendedAll_l(bool suspend)
+{
+    sp<SuspendedEffectDesc> desc;
+
+    int index = mSuspendedEffects.indexOfKey((int)kKeyForSuspendAll);
+    if (suspend) {
+        if (index >= 0) {
+            desc = mSuspendedEffects.valueAt(index);
+        } else {
+            desc = new SuspendedEffectDesc();
+            mSuspendedEffects.add((int)kKeyForSuspendAll, desc);
+            LOGV("setEffectSuspendedAll_l() add entry for 0");
+        }
+        if (desc->mRefCount++ == 0) {
+            Vector< sp<EffectModule> > effects = getSuspendEligibleEffects();
+            for (size_t i = 0; i < effects.size(); i++) {
+                setEffectSuspended_l(&effects[i]->desc().type, true);
+            }
+        }
+    } else {
+        if (index < 0) {
+            return;
+        }
+        desc = mSuspendedEffects.valueAt(index);
+        if (desc->mRefCount <= 0) {
+            LOGW("setEffectSuspendedAll_l() restore refcount should not be 0 %d", desc->mRefCount);
+            desc->mRefCount = 1;
+        }
+        if (--desc->mRefCount == 0) {
+            Vector<const effect_uuid_t *> types;
+            for (size_t i = 0; i < mSuspendedEffects.size(); i++) {
+                if (mSuspendedEffects.keyAt(i) == (int)kKeyForSuspendAll) {
+                    continue;
+                }
+                types.add(&mSuspendedEffects.valueAt(i)->mType);
+            }
+            for (size_t i = 0; i < types.size(); i++) {
+                setEffectSuspended_l(types[i], false);
+            }
+            LOGV("setEffectSuspendedAll_l() remove entry for %08x", mSuspendedEffects.keyAt(index));
+            mSuspendedEffects.removeItem((int)kKeyForSuspendAll);
+        }
+    }
+}
+
+Vector< sp<AudioFlinger::EffectModule> > AudioFlinger::EffectChain::getSuspendEligibleEffects()
+{
+    Vector< sp<EffectModule> > effects;
+    for (size_t i = 0; i < mEffects.size(); i++) {
+        effect_descriptor_t desc = mEffects[i]->desc();
+        // auxiliary effects and vizualizer are never suspended on output mix
+        if ((mSessionId == AUDIO_SESSION_OUTPUT_MIX) && (
+            ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) ||
+             (memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0))) {
+            continue;
+        }
+        effects.add(mEffects[i]);
+    }
+    return effects;
+}
+
+sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectIfEnabled(
+                                                            const effect_uuid_t *type)
+{
+    sp<EffectModule> effect;
+    effect = getEffectFromType_l(type);
+    if (effect != 0 && !effect->isEnabled()) {
+        effect.clear();
+    }
+    return effect;
+}
+
+void AudioFlinger::EffectChain::checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
+                                                            bool enabled)
+{
+    int index = mSuspendedEffects.indexOfKey(effect->desc().type.timeLow);
+    if (enabled) {
+        if (index < 0) {
+            // if the effect is not suspend check if all effects are suspended
+            index = mSuspendedEffects.indexOfKey((int)kKeyForSuspendAll);
+            if (index < 0) {
+                return;
+            }
+            setEffectSuspended_l(&effect->desc().type, enabled);
+            index = mSuspendedEffects.indexOfKey(effect->desc().type.timeLow);
+        }
+        LOGV("checkSuspendOnEffectEnabled() enable suspending fx %08x",
+             effect->desc().type.timeLow);
+        sp<SuspendedEffectDesc> desc = mSuspendedEffects.valueAt(index);
+        // if effect is requested to suspended but was not yet enabled, supend it now.
+        if (desc->mEffect == 0) {
+            desc->mEffect = effect;
+            effect->setEnabled(false);
+            effect->setSuspended(true);
+        }
+    } else {
+        if (index < 0) {
+            return;
+        }
+        LOGV("checkSuspendOnEffectEnabled() disable restoring fx %08x",
+             effect->desc().type.timeLow);
+        sp<SuspendedEffectDesc> desc = mSuspendedEffects.valueAt(index);
+        desc->mEffect.clear();
+        effect->setSuspended(false);
+    }
+}
+
 #undef LOG_TAG
 #define LOG_TAG "AudioFlinger"
 
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 80a9945..4fa70a2 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -165,7 +165,7 @@
                         int *id,
                         int *enabled);
 
-    virtual status_t moveEffects(int session, int srcOutput, int dstOutput);
+    virtual status_t moveEffects(int sessionId, int srcOutput, int dstOutput);
 
     enum hardware_call_state {
         AUDIO_HW_IDLE = 0,
@@ -206,6 +206,8 @@
 
                 uint32_t    getMode() { return mMode; }
 
+                bool        btNrec() { return mBtNrec; }
+
 private:
                             AudioFlinger();
     virtual                 ~AudioFlinger();
@@ -477,14 +479,45 @@
                     // strategy is only meaningful for PlaybackThread which implements this method
                     virtual uint32_t getStrategyForSession_l(int sessionId) { return 0; }
 
+                    // suspend or restore effect according to the type of effect passed. a NULL
+                    // type pointer means suspend all effects in the session
+                    void setEffectSuspended(const effect_uuid_t *type,
+                                            bool suspend,
+                                            int sessionId = AUDIO_SESSION_OUTPUT_MIX);
+                    // check if some effects must be suspended/restored when an effect is enabled
+                    // or disabled
+        virtual     void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
+                                                     bool enabled,
+                                                     int sessionId = AUDIO_SESSION_OUTPUT_MIX);
+
         mutable     Mutex                   mLock;
 
     protected:
 
+                    // entry describing an effect being suspended in mSuspendedSessions keyed vector
+                    class SuspendedSessionDesc : public RefBase {
+                    public:
+                        SuspendedSessionDesc() : mRefCount(0) {}
+
+                        int mRefCount;          // number of active suspend requests
+                        effect_uuid_t mType;    // effect type UUID
+                    };
+
                     void        acquireWakeLock();
                     void        acquireWakeLock_l();
                     void        releaseWakeLock();
                     void        releaseWakeLock_l();
+                    void setEffectSuspended_l(const effect_uuid_t *type,
+                                              bool suspend,
+                                              int sessionId = AUDIO_SESSION_OUTPUT_MIX);
+                    // updated mSuspendedSessions when an effect suspended or restored
+                    void        updateSuspendedSessions_l(const effect_uuid_t *type,
+                                                          bool suspend,
+                                                          int sessionId);
+                    // check if some effects must be suspended when an effect chain is added
+                    void checkSuspendOnAddEffectChain_l(const sp<EffectChain>& chain);
+                    // updated mSuspendedSessions when an effect chain is removed
+                    void updateSuspendedSessionsOnRemoveEffectChain_l(const sp<EffectChain>& chain);
 
         friend class Track;
         friend class TrackBase;
@@ -519,6 +552,9 @@
                     sp<IPowerManager>       mPowerManager;
                     sp<IBinder>             mWakeLockToken;
                     sp<PMDeathRecipient>    mDeathRecipient;
+                    // list of suspended effects per session and per type. The first vector is
+                    // keyed by session ID, the second by type UUID timeLow field
+                    KeyedVector< int, KeyedVector< int, sp<SuspendedSessionDesc> > >  mSuspendedSessions;
     };
 
     // --- PlaybackThread ---
@@ -849,7 +885,7 @@
               void audioConfigChanged_l(int event, int ioHandle, void *param2);
 
               uint32_t nextUniqueId();
-              status_t moveEffectChain_l(int session,
+              status_t moveEffectChain_l(int sessionId,
                                      AudioFlinger::PlaybackThread *srcThread,
                                      AudioFlinger::PlaybackThread *dstThread,
                                      bool reRegister);
@@ -909,6 +945,7 @@
                     bool        setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
 
                     void        dump(char* buffer, size_t size);
+
         private:
             friend class AudioFlinger;
             friend class RecordThread;
@@ -952,8 +989,6 @@
                 AudioStreamIn* clearInput();
                 virtual audio_stream_t* stream();
 
-
-                void        setTrack(RecordTrack *recordTrack) { mTrack = recordTrack; }
         virtual status_t    getNextBuffer(AudioBufferProvider::Buffer* buffer);
         virtual void        releaseBuffer(AudioBufferProvider::Buffer* buffer);
         virtual bool        checkForNewParameters_l();
@@ -965,6 +1000,7 @@
         virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
         virtual size_t removeEffectChain_l(const sp<EffectChain>& chain);
         virtual uint32_t hasAudioSession(int sessionId);
+                RecordTrack* track();
 
     private:
                 RecordThread();
@@ -1061,6 +1097,7 @@
         int16_t     *outBuffer() { return mConfig.outputCfg.buffer.s16; }
         void        setChain(const wp<EffectChain>& chain) { mChain = chain; }
         void        setThread(const wp<ThreadBase>& thread) { mThread = thread; }
+        wp<ThreadBase>& thread() { return mThread; }
 
         status_t addHandle(sp<EffectHandle>& handle);
         void disconnect(const wp<EffectHandle>& handle);
@@ -1073,6 +1110,10 @@
         status_t         setVolume(uint32_t *left, uint32_t *right, bool controller);
         status_t         setMode(uint32_t mode);
         status_t         stop();
+        void             setSuspended(bool suspended);
+        bool             suspended();
+
+        sp<EffectHandle> controlHandle();
 
         status_t         dump(int fd, const Vector<String16>& args);
 
@@ -1101,6 +1142,7 @@
         uint32_t mMaxDisableWaitCnt;    // maximum grace period before forcing an effect off after
                                         // sending disable command.
         uint32_t mDisableWaitCnt;       // current process() calls count during disable period.
+        bool     mSuspended;            // effect is suspended: temporarily disabled by framework
     };
 
     // The EffectHandle class implements the IEffect interface. It provides resources
@@ -1133,13 +1175,17 @@
 
 
         // Give or take control of effect module
-        void setControl(bool hasControl, bool signal);
+        // - hasControl: true if control is given, false if removed
+        // - signal: true client app should be signaled of change, false otherwise
+        // - enabled: state of the effect when control is passed
+        void setControl(bool hasControl, bool signal, bool enabled);
         void commandExecuted(uint32_t cmdCode,
                              uint32_t cmdSize,
                              void *pCmdData,
                              uint32_t replySize,
                              void *pReplyData);
         void setEnabled(bool enabled);
+        bool enabled() { return mEnabled; }
 
         // Getters
         int id() { return mEffect->id(); }
@@ -1162,6 +1208,8 @@
         uint8_t*            mBuffer;        // pointer to parameter area in shared memory
         int mPriority;                      // client application priority to control the effect
         bool mHasControl;                   // true if this handle is controlling the effect
+        bool mEnabled;                      // cached enable state: needed when the effect is
+                                            // restored after being suspended
     };
 
     // the EffectChain class represents a group of effects associated to one audio session.
@@ -1176,6 +1224,10 @@
         EffectChain(const wp<ThreadBase>& wThread, int sessionId);
         ~EffectChain();
 
+        // special key used for an entry in mSuspendedEffects keyed vector
+        // corresponding to a suspend all request.
+        static const int        kKeyForSuspendAll = 0;
+
         void process_l();
 
         void lock() {
@@ -1193,6 +1245,7 @@
 
         sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor);
         sp<EffectModule> getEffectFromId_l(int id);
+        sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type);
         bool setVolume_l(uint32_t *left, uint32_t *right);
         void setDevice_l(uint32_t device);
         void setMode_l(uint32_t mode);
@@ -1223,6 +1276,15 @@
         void setStrategy(uint32_t strategy)
                  { mStrategy = strategy; }
 
+        // suspend effect of the given type
+        void setEffectSuspended_l(const effect_uuid_t *type,
+                                  bool suspend);
+        // suspend all eligible effects
+        void setEffectSuspendedAll_l(bool suspend);
+        // check if effects should be suspend or restored when a given effect is enable or disabled
+        virtual void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
+                                              bool enabled);
+
         status_t dump(int fd, const Vector<String16>& args);
 
     protected:
@@ -1230,6 +1292,21 @@
         EffectChain(const EffectChain&);
         EffectChain& operator =(const EffectChain&);
 
+        class SuspendedEffectDesc : public RefBase {
+        public:
+            SuspendedEffectDesc() : mRefCount(0) {}
+
+            int mRefCount;
+            effect_uuid_t mType;
+            wp<EffectModule> mEffect;
+        };
+
+        // get a list of effect modules to suspend when an effect of the type
+        // passed is enabled.
+        Vector< sp<EffectModule> > getSuspendEligibleEffects();
+        // get an effect module if it is currently enable
+        sp<EffectModule> getEffectIfEnabled(const effect_uuid_t *type);
+
         wp<ThreadBase> mThread;     // parent mixer thread
         Mutex mLock;                // mutex protecting effect list
         Vector<sp<EffectModule> > mEffects; // list of effect modules
@@ -1245,6 +1322,10 @@
         uint32_t mNewLeftVolume;       // new volume on left channel
         uint32_t mNewRightVolume;      // new volume on right channel
         uint32_t mStrategy; // strategy for this effect chain
+        // mSuspendedEffects lists all effect currently suspended in the chain
+        // use effect type UUID timelow field as key. There is no real risk of identical
+        // timeLow fields among effect type UUIDs.
+        KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects;
     };
 
     struct AudioStreamOut {
@@ -1285,7 +1366,8 @@
 
                 DefaultKeyedVector< pid_t, sp<NotificationClient> >    mNotificationClients;
                 volatile int32_t                    mNextUniqueId;
-                uint32_t mMode;
+                uint32_t                            mMode;
+                bool                                mBtNrec;
 
 };
 
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 2e3d6dd..8b7d3a8 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -2034,6 +2034,15 @@
                 boolean compressing = COMPRESS_FULL_BACKUPS;
                 OutputStream finalOutput = ofstream;
 
+                // Verify that the given password matches the currently-active
+                // backup password, if any
+                if (hasBackupPassword()) {
+                    if (!passwordMatchesSaved(mCurrentPassword, PBKDF2_HASH_ROUNDS)) {
+                        if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
+                        return;
+                    }
+                }
+
                 // Write the global file header.  All strings are UTF-8 encoded; lines end
                 // with a '\n' byte.  Actual backup data begins immediately following the
                 // final '\n'.
@@ -2068,15 +2077,6 @@
                 try {
                     // Set up the encryption stage if appropriate, and emit the correct header
                     if (encrypting) {
-                        // Verify that the given password matches the currently-active
-                        // backup password, if any
-                        if (hasBackupPassword()) {
-                            if (!passwordMatchesSaved(mCurrentPassword, PBKDF2_HASH_ROUNDS)) {
-                                if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
-                                return;
-                            }
-                        }
-
                         finalOutput = emitAesBackupHeader(headerbuf, finalOutput);
                     } else {
                         headerbuf.append("none\n");
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 541a8cf..3ae7a3f 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -40,6 +40,7 @@
 import android.net.NetworkConfig;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkQuotaInfo;
 import android.net.NetworkState;
 import android.net.NetworkStateTracker;
 import android.net.NetworkUtils;
@@ -253,6 +254,12 @@
     private static final int EVENT_RESTORE_DNS =
             MAX_NETWORK_STATE_TRACKER_EVENT + 11;
 
+    /**
+     * used internally to send a sticky broadcast delayed.
+     */
+    private static final int EVENT_SEND_STICKY_BROADCAST_INTENT =
+            MAX_NETWORK_STATE_TRACKER_EVENT + 12;
+
     private Handler mHandler;
 
     // list of DeathRecipients used to make sure features are turned off when
@@ -344,7 +351,7 @@
             mPolicyManager.registerListener(mPolicyListener);
         } catch (RemoteException e) {
             // ouch, no rules updates means some processes may never get network
-            Slog.e(TAG, "unable to register INetworkPolicyListener", e);
+            loge("unable to register INetworkPolicyListener" + e.toString());
         }
 
         final PowerManager powerManager = (PowerManager) context.getSystemService(
@@ -558,6 +565,17 @@
         }
     }
 
+    private int getConnectivityChangeDelay() {
+        final ContentResolver cr = mContext.getContentResolver();
+
+        /** Check system properties for the default value then use secure settings value, if any. */
+        int defaultDelay = SystemProperties.getInt(
+                "conn." + Settings.Secure.CONNECTIVITY_CHANGE_DELAY,
+                Settings.Secure.CONNECTIVITY_CHANGE_DELAY_DEFAULT);
+        return Settings.Secure.getInt(cr, Settings.Secure.CONNECTIVITY_CHANGE_DELAY,
+                defaultDelay);
+    }
+
     private int getPersistedNetworkPreference() {
         final ContentResolver cr = mContext.getContentResolver();
 
@@ -737,6 +755,30 @@
         return result.toArray(new NetworkState[result.size()]);
     }
 
+    private NetworkState getNetworkStateUnchecked(int networkType) {
+        if (isNetworkTypeValid(networkType)) {
+            final NetworkStateTracker tracker = mNetTrackers[networkType];
+            if (tracker != null) {
+                return new NetworkState(tracker.getNetworkInfo(), tracker.getLinkProperties(),
+                        tracker.getLinkCapabilities());
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
+        enforceAccessPermission();
+        final NetworkState state = getNetworkStateUnchecked(mActiveDefaultNetwork);
+        if (state != null) {
+            try {
+                return mPolicyManager.getNetworkQuotaInfo(state);
+            } catch (RemoteException e) {
+            }
+        }
+        return null;
+    }
+
     public boolean setRadios(boolean turnOn) {
         boolean result = true;
         enforceChangePermission();
@@ -798,9 +840,11 @@
         }
 
         public void expire() {
-            log("ConnectivityService FeatureUser expire(" +
-                    mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
-                    (System.currentTimeMillis() - mCreateTime) + " mSec ago");
+            if (VDBG) {
+                log("ConnectivityService FeatureUser expire(" +
+                        mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
+                        (System.currentTimeMillis() - mCreateTime) + " mSec ago");
+            }
             stopUsingNetworkFeature(this, false);
         }
 
@@ -843,7 +887,7 @@
         if(networkType == ConnectivityManager.TYPE_MOBILE) {
             usedNetworkType = convertFeatureToNetworkType(feature);
             if (usedNetworkType < 0) {
-                Slog.e(TAG, "Can't match any netTracker!");
+                loge("Can't match any netTracker!");
                 usedNetworkType = networkType;
             }
         }
@@ -953,7 +997,7 @@
             return stopUsingNetworkFeature(u, true);
         } else {
             // none found!
-            if (DBG) log("ignoring stopUsingNetworkFeature - not a live request");
+            if (VDBG) log("ignoring stopUsingNetworkFeature - not a live request");
             return 1;
         }
     }
@@ -1081,7 +1125,7 @@
 
         if (tracker == null || !tracker.getNetworkInfo().isConnected() ||
                 tracker.isTeardownRequested()) {
-            if (DBG) {
+            if (VDBG) {
                 log("requestRouteToHostAddress on down network " +
                            "(" + networkType + ") - dropped");
             }
@@ -1152,13 +1196,13 @@
             }
         }
         if (doAdd) {
-            if (DBG) log("Adding " + r + " for interface " + ifaceName);
+            if (VDBG) log("Adding " + r + " for interface " + ifaceName);
             mAddedRoutes.add(r);
             try {
                 mNetd.addRoute(ifaceName, r);
             } catch (Exception e) {
                 // never crash - catch them all
-                loge("Exception trying to add a route: " + e);
+                if (VDBG) loge("Exception trying to add a route: " + e);
                 return false;
             }
         } else {
@@ -1166,16 +1210,16 @@
             // we can remove it from the table
             mAddedRoutes.remove(r);
             if (mAddedRoutes.contains(r) == false) {
-                if (DBG) log("Removing " + r + " for interface " + ifaceName);
+                if (VDBG) log("Removing " + r + " for interface " + ifaceName);
                 try {
                     mNetd.removeRoute(ifaceName, r);
                 } catch (Exception e) {
                     // never crash - catch them all
-                    loge("Exception trying to remove a route: " + e);
+                    if (VDBG) loge("Exception trying to remove a route: " + e);
                     return false;
                 }
             } else {
-                if (DBG) log("not removing " + r + " as it's still in use");
+                if (VDBG) log("not removing " + r + " as it's still in use");
             }
         }
         return true;
@@ -1220,7 +1264,7 @@
         enforceAccessPermission();
         boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
                 Settings.Secure.MOBILE_DATA, 1) == 1;
-        if (DBG) log("getMobileDataEnabled returning " + retVal);
+        if (VDBG) log("getMobileDataEnabled returning " + retVal);
         return retVal;
     }
 
@@ -1247,7 +1291,7 @@
             mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
 
             if (LOGD_RULES) {
-                Slog.d(TAG, "onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
+                log("onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
             }
 
             synchronized (mRulesLock) {
@@ -1268,8 +1312,7 @@
             mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
 
             if (LOGD_RULES) {
-                Slog.d(TAG,
-                        "onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")");
+                log("onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")");
             }
 
             synchronized (mRulesLock) {
@@ -1294,8 +1337,8 @@
 
     private void handleSetMobileData(boolean enabled) {
         if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
-            if (DBG) {
-                Slog.d(TAG, mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled);
+            if (VDBG) {
+                log(mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled);
             }
             mNetTrackers[ConnectivityManager.TYPE_MOBILE].setDataEnable(enabled);
         }
@@ -1411,13 +1454,14 @@
         // do this before we broadcast the change
         handleConnectivityChange(prevNetType, doReset);
 
-        sendStickyBroadcast(intent);
+        sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay());
         /*
          * If the failover network is already connected, then immediately send
          * out a followup broadcast indicating successful failover
          */
         if (mActiveDefaultNetwork != -1) {
-            sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo());
+            sendConnectedBroadcastDelayed(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(),
+                    getConnectivityChangeDelay());
         }
     }
 
@@ -1471,11 +1515,15 @@
         sendGeneralBroadcast(info, ConnectivityManager.CONNECTIVITY_ACTION);
     }
 
+    private void sendConnectedBroadcastDelayed(NetworkInfo info, int delayMs) {
+        sendGeneralBroadcastDelayed(info, ConnectivityManager.CONNECTIVITY_ACTION, delayMs);
+    }
+
     private void sendInetConditionBroadcast(NetworkInfo info) {
         sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION);
     }
 
-    private void sendGeneralBroadcast(NetworkInfo info, String bcastType) {
+    private Intent makeGeneralIntent(NetworkInfo info, String bcastType) {
         Intent intent = new Intent(bcastType);
         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
         if (info.isFailover()) {
@@ -1490,7 +1538,15 @@
                     info.getExtraInfo());
         }
         intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
-        sendStickyBroadcast(intent);
+        return intent;
+    }
+
+    private void sendGeneralBroadcast(NetworkInfo info, String bcastType) {
+        sendStickyBroadcast(makeGeneralIntent(info, bcastType));
+    }
+
+    private void sendGeneralBroadcastDelayed(NetworkInfo info, String bcastType, int delayMs) {
+        sendStickyBroadcastDelayed(makeGeneralIntent(info, bcastType), delayMs);
     }
 
     /**
@@ -1555,10 +1611,25 @@
                 mInitialBroadcast = new Intent(intent);
             }
             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+            if (DBG) {
+                log("sendStickyBroadcast: NetworkInfo=" +
+                    intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO));
+            }
+
             mContext.sendStickyBroadcast(intent);
         }
     }
 
+    private void sendStickyBroadcastDelayed(Intent intent, int delayMs) {
+        if (delayMs <= 0) {
+            sendStickyBroadcast(intent);
+        } else {
+            if (DBG) log("sendStickyBroadcastDelayed: delayMs=" + delayMs + " intent=" + intent);
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(
+                    EVENT_SEND_STICKY_BROADCAST_INTENT, intent), delayMs);
+        }
+    }
+
     void systemReady() {
         synchronized(this) {
             mSystemReady = true;
@@ -1587,7 +1658,7 @@
                         mNetConfigs[type].priority) ||
                         mNetworkPreference == mActiveDefaultNetwork) {
                         // don't accept this one
-                        if (DBG) {
+                        if (VDBG) {
                             log("Not broadcasting CONNECT_ACTION " +
                                 "to torn down network " + info.getTypeName());
                         }
@@ -1632,7 +1703,7 @@
         thisNet.setTeardownRequested(false);
         updateNetworkSettings(thisNet);
         handleConnectivityChange(type, false);
-        sendConnectedBroadcast(info);
+        sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
     }
 
     /**
@@ -1688,9 +1759,11 @@
                     }
                 } else {
                     resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
-                    log("handleConnectivityChange: interface not not equivalent reset both" +
-                            " linkProperty[" + netType + "]:" +
-                            " resetMask=" + resetMask);
+                    if (DBG) {
+                        log("handleConnectivityChange: interface not not equivalent reset both" +
+                                " linkProperty[" + netType + "]:" +
+                                " resetMask=" + resetMask);
+                    }
                 }
             }
             if (mNetConfigs[netType].isDefault()) {
@@ -1798,7 +1871,7 @@
         String bufferSizes = SystemProperties.get(key);
 
         if (bufferSizes.length() == 0) {
-            loge(key + " not found in system properties. Using defaults");
+            if (VDBG) log(key + " not found in system properties. Using defaults");
 
             // Setting to default values so we won't be stuck to previous values
             key = "net.tcp.buffersize.default";
@@ -1807,7 +1880,7 @@
 
         // Set values in kernel
         if (bufferSizes.length() != 0) {
-            if (DBG) {
+            if (VDBG) {
                 log("Setting TCP values: [" + bufferSizes
                         + "] which comes from [" + key + "]");
             }
@@ -1849,7 +1922,7 @@
      */
     private void reassessPidDns(int myPid, boolean doBump)
     {
-        if (DBG) log("reassessPidDns for pid " + myPid);
+        if (VDBG) log("reassessPidDns for pid " + myPid);
         for(int i : mPriorityList) {
             if (mNetConfigs[i].isDefault()) {
                 continue;
@@ -1935,7 +2008,7 @@
             String value = mDefaultDns.getHostAddress();
             if (!value.equals(SystemProperties.get("net.dns1"))) {
                 if (DBG) {
-                    log("no dns provided for " + network + " - using " + value);
+                    loge("no dns provided for " + network + " - using " + value);
                 }
                 changed = true;
                 SystemProperties.set("net.dns1", value);
@@ -1948,7 +2021,7 @@
                 if (!changed && value.equals(SystemProperties.get(key))) {
                     continue;
                 }
-                if (DBG) {
+                if (VDBG) {
                     log("adding dns " + value + " for " + network);
                 }
                 changed = true;
@@ -1957,7 +2030,7 @@
         }
         for (int i = last + 1; i <= mNumDnsEntries; ++i) {
             String key = "net.dns" + i;
-            if (DBG) log("erasing " + key);
+            if (VDBG) log("erasing " + key);
             changed = true;
             SystemProperties.set(key, "");
         }
@@ -1968,7 +2041,7 @@
                 mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses));
                 mNetd.setDefaultInterfaceForDns(iface);
             } catch (Exception e) {
-                Slog.e(TAG, "exception setting default dns interface: " + e);
+                loge("exception setting default dns interface: " + e);
             }
         }
         if (!domains.equals(SystemProperties.get("net.dns.search"))) {
@@ -1998,7 +2071,7 @@
                     mNetd.setDnsServersForInterface(p.getInterfaceName(),
                             NetworkUtils.makeStrings(dnses));
                 } catch (Exception e) {
-                    Slog.e(TAG, "exception setting dns servers: " + e);
+                    loge("exception setting dns servers: " + e);
                 }
                 // set per-pid dns for attached secondary nets
                 List pids = mNetRequestersPids[netType];
@@ -2212,6 +2285,13 @@
                     }
                     break;
                 }
+                case EVENT_SEND_STICKY_BROADCAST_INTENT:
+                {
+                    Intent intent = (Intent)msg.obj;
+                    log("EVENT_SEND_STICKY_BROADCAST_INTENT: sendStickyBroadcast intent=" + intent);
+                    sendStickyBroadcast(intent);
+                    break;
+                }
             }
         }
     }
@@ -2335,7 +2415,7 @@
 
     // 100 percent is full good, 0 is full bad.
     public void reportInetCondition(int networkType, int percentage) {
-        if (DBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")");
+        if (VDBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")");
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.STATUS_BAR,
                 "ConnectivityService");
@@ -2372,7 +2452,7 @@
         mDefaultInetCondition = condition;
         int delay;
         if (mInetConditionChangeInFlight == false) {
-            if (DBG) log("starting a change hold");
+            if (VDBG) log("starting a change hold");
             // setup a new hold to debounce this
             if (mDefaultInetCondition > 50) {
                 delay = Settings.Secure.getInt(mContext.getContentResolver(),
@@ -2387,12 +2467,12 @@
         } else {
             // we've set the new condition, when this hold ends that will get
             // picked up
-            if (DBG) log("currently in hold - not setting new end evt");
+            if (VDBG) log("currently in hold - not setting new end evt");
         }
     }
 
     private void handleInetConditionHoldEnd(int netType, int sequence) {
-        if (DBG) {
+        if (VDBG) {
             log("Inet hold end, net=" + netType +
                     ", condition =" + mDefaultInetCondition +
                     ", published condition =" + mDefaultInetConditionPublished);
@@ -2407,10 +2487,13 @@
             if (DBG) log("event hold for obsolete network - aborting");
             return;
         }
-        if (mDefaultInetConditionPublished == mDefaultInetCondition) {
-            if (DBG) log("no change in condition - aborting");
-            return;
-        }
+        // TODO: Figure out why this optimization sometimes causes a
+        //       change in mDefaultInetCondition to be missed and the
+        //       UI to not be updated.
+        //if (mDefaultInetConditionPublished == mDefaultInetCondition) {
+        //    if (DBG) log("no change in condition - aborting");
+        //    return;
+        //}
         NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
         if (networkInfo.isConnected() == false) {
             if (DBG) log("default network not connected - aborting");
@@ -2490,7 +2573,7 @@
                 mDefaultProxy = null;
             }
         }
-        if (DBG) log("changing default proxy to " + proxy);
+        if (VDBG) log("changing default proxy to " + proxy);
         if ((proxy == null && mGlobalProxy == null) || proxy.equals(mGlobalProxy)) return;
         if (mGlobalProxy != null) return;
         sendProxyBroadcast(proxy);
@@ -2517,7 +2600,7 @@
 
     private void sendProxyBroadcast(ProxyProperties proxy) {
         if (proxy == null) proxy = new ProxyProperties("", 0, "");
-        log("sending Proxy Broadcast for " + proxy);
+        if (DBG) log("sending Proxy Broadcast for " + proxy);
         Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
             Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index 88d94c2..fed554c 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -19,6 +19,9 @@
 import android.net.LocalSocketAddress;
 import android.net.LocalSocket;
 import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.util.Slog;
@@ -39,7 +42,7 @@
  * daemon which uses the libsysutils FrameworkListener
  * protocol.
  */
-final class NativeDaemonConnector implements Runnable {
+final class NativeDaemonConnector implements Runnable, Handler.Callback {
     private static final boolean LOCAL_LOGD = false;
 
     private BlockingQueue<String> mResponseQueue;
@@ -47,6 +50,7 @@
     private String                TAG = "NativeDaemonConnector";
     private String                mSocket;
     private INativeDaemonConnectorCallbacks mCallbacks;
+    private Handler               mCallbackHandler;
 
     private final int BUFFER_SIZE = 4096;
 
@@ -76,7 +80,11 @@
         mResponseQueue = new LinkedBlockingQueue<String>(responseQueueSize);
     }
 
+    @Override
     public void run() {
+        HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler");
+        thread.start();
+        mCallbackHandler = new Handler(thread.getLooper(), this);
 
         while (true) {
             try {
@@ -88,6 +96,21 @@
         }
     }
 
+    @Override
+    public boolean handleMessage(Message msg) {
+        String event = (String) msg.obj;
+        try {
+            if (!mCallbacks.onEvent(msg.what, event, event.split(" "))) {
+                Slog.w(TAG, String.format(
+                        "Unhandled event '%s'", event));
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, String.format(
+                    "Error handling '%s'", event), e);
+        }
+        return true;
+    }
+
     private void listenToSocket() throws IOException {
         LocalSocket socket = null;
 
@@ -119,20 +142,13 @@
                         String event = new String(buffer, start, i - start);
                         if (LOCAL_LOGD) Slog.d(TAG, String.format("RCV <- {%s}", event));
 
-                        String[] tokens = event.split(" ");
+                        String[] tokens = event.split(" ", 2);
                         try {
                             int code = Integer.parseInt(tokens[0]);
 
                             if (code >= ResponseCode.UnsolicitedInformational) {
-                                try {
-                                    if (!mCallbacks.onEvent(code, event, tokens)) {
-                                        Slog.w(TAG, String.format(
-                                                "Unhandled event (%s)", event));
-                                    }
-                                } catch (Exception ex) {
-                                    Slog.e(TAG, String.format(
-                                            "Error handling '%s'", event), ex);
-                                }
+                                mCallbackHandler.sendMessage(
+                                        mCallbackHandler.obtainMessage(code, event));
                             } else {
                                 try {
                                     mResponseQueue.put(event);
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index a59b6c0..30de385 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -1231,6 +1231,13 @@
         }
     }
 
+    @Override
+    public boolean isBandwidthControlEnabled() {
+        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+        return mBandwidthControlEnabled;
+    }
+
+    @Override
     public NetworkStats getNetworkStatsUidDetail(int uid) {
         if (Binder.getCallingUid() != uid) {
             mContext.enforceCallingOrSelfPermission(
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 8031c4e..6edb132 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -325,6 +325,7 @@
             
             if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
+                    || action.equals(Intent.ACTION_PACKAGE_CHANGED)
                     || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
                     || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
                 String pkgList[] = null;
@@ -430,6 +431,7 @@
         mContext.registerReceiver(mIntentReceiver, filter);
         IntentFilter pkgFilter = new IntentFilter();
         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
         pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
         pkgFilter.addDataScheme("package");
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index f15eca6..4a0dcdf 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -27,6 +27,7 @@
 import android.content.pm.IPackageManager;
 import android.content.res.Configuration;
 import android.media.AudioService;
+import android.net.wifi.p2p.WifiP2pService;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -37,7 +38,6 @@
 import android.server.BluetoothA2dpService;
 import android.server.BluetoothService;
 import android.server.search.SearchManagerService;
-import android.server.WifiP2pService;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Slog;
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
index e97df84..90824a6 100644
--- a/services/java/com/android/server/TextServicesManagerService.java
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -23,6 +23,8 @@
 import com.android.internal.textservice.ITextServicesManager;
 import com.android.internal.textservice.ITextServicesSessionListener;
 
+import org.xmlpull.v1.XmlPullParserException;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -31,19 +33,18 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.provider.Settings;
-import android.text.TextUtils;
 import android.service.textservice.SpellCheckerService;
-import android.util.Log;
+import android.text.TextUtils;
 import android.util.Slog;
 import android.view.textservice.SpellCheckerInfo;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 
 public class TextServicesManagerService extends ITextServicesManager.Stub {
@@ -127,9 +128,15 @@
                 continue;
             }
             if (DBG) Slog.d(TAG, "Add: " + compName);
-            final SpellCheckerInfo sci = new SpellCheckerInfo(context, ri);
-            list.add(sci);
-            map.put(sci.getId(), sci);
+            try {
+                final SpellCheckerInfo sci = new SpellCheckerInfo(context, ri);
+                list.add(sci);
+                map.put(sci.getId(), sci);
+            } catch (XmlPullParserException e) {
+                Slog.w(TAG, "Unable to load the spell checker " + compName, e);
+            } catch (IOException e) {
+                Slog.w(TAG, "Unable to load the spell checker " + compName, e);
+            }
         }
         if (DBG) {
             Slog.d(TAG, "buildSpellCheckerMapLocked: " + list.size() + "," + map.size());
@@ -180,7 +187,8 @@
 
     @Override
     public void getSpellCheckerService(String sciId, String locale,
-            ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener) {
+            ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener,
+            Bundle bundle) {
         if (!mSystemReady) {
             return;
         }
@@ -199,7 +207,7 @@
                 if (bindGroup != null) {
                     final InternalDeathRecipient recipient =
                             mSpellCheckerBindGroups.get(sciId).addListener(
-                                    tsListener, locale, scListener, uid);
+                                    tsListener, locale, scListener, uid, bundle);
                     if (recipient == null) {
                         if (DBG) {
                             Slog.w(TAG, "Didn't create a death recipient.");
@@ -217,7 +225,7 @@
                         try {
                             final ISpellCheckerSession session =
                                     bindGroup.mSpellChecker.getISpellCheckerSession(
-                                            recipient.mScLocale, recipient.mScListener);
+                                            recipient.mScLocale, recipient.mScListener, bundle);
                             if (session != null) {
                                 tsListener.onServiceConnected(session);
                                 return;
@@ -236,7 +244,8 @@
             }
             final long ident = Binder.clearCallingIdentity();
             try {
-                startSpellCheckerServiceInnerLocked(sci, locale, tsListener, scListener, uid);
+                startSpellCheckerServiceInnerLocked(
+                        sci, locale, tsListener, scListener, uid, bundle);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -246,13 +255,13 @@
 
     private void startSpellCheckerServiceInnerLocked(SpellCheckerInfo info, String locale,
             ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener,
-            int uid) {
+            int uid, Bundle bundle) {
         if (DBG) {
             Slog.w(TAG, "Start spell checker session inner locked.");
         }
         final String sciId = info.getId();
         final InternalServiceConnection connection = new InternalServiceConnection(
-                sciId, locale, scListener);
+                sciId, locale, scListener, bundle);
         final Intent serviceIntent = new Intent(SpellCheckerService.SERVICE_INTERFACE);
         serviceIntent.setComponent(info.getComponent());
         if (DBG) {
@@ -263,7 +272,7 @@
             return;
         }
         final SpellCheckerBindGroup group = new SpellCheckerBindGroup(
-                connection, tsListener, locale, scListener, uid);
+                connection, tsListener, locale, scListener, uid, bundle);
         mSpellCheckerBindGroups.put(sciId, group);
     }
 
@@ -332,10 +341,10 @@
 
         public SpellCheckerBindGroup(InternalServiceConnection connection,
                 ITextServicesSessionListener listener, String locale,
-                ISpellCheckerSessionListener scListener, int uid) {
+                ISpellCheckerSessionListener scListener, int uid, Bundle bundle) {
             mInternalConnection = connection;
             mConnected = false;
-            addListener(listener, locale, scListener, uid);
+            addListener(listener, locale, scListener, uid, bundle);
         }
 
         public void onServiceConnected(ISpellCheckerService spellChecker) {
@@ -346,7 +355,7 @@
                 for (InternalDeathRecipient listener : mListeners) {
                     try {
                         final ISpellCheckerSession session = spellChecker.getISpellCheckerSession(
-                                listener.mScLocale, listener.mScListener);
+                                listener.mScLocale, listener.mScListener, listener.mBundle);
                         listener.mTsListener.onServiceConnected(session);
                     } catch (RemoteException e) {
                         Slog.e(TAG, "Exception in getting the spell checker session: " + e);
@@ -360,7 +369,7 @@
         }
 
         public InternalDeathRecipient addListener(ITextServicesSessionListener tsListener,
-                String locale, ISpellCheckerSessionListener scListener, int uid) {
+                String locale, ISpellCheckerSessionListener scListener, int uid, Bundle bundle) {
             if (DBG) {
                 Slog.d(TAG, "addListener: " + locale);
             }
@@ -375,7 +384,7 @@
                         }
                     }
                     recipient = new InternalDeathRecipient(
-                            this, tsListener, locale, scListener, uid);
+                            this, tsListener, locale, scListener, uid, bundle);
                     scListener.asBinder().linkToDeath(recipient, 0);
                     mListeners.add(recipient);
                 } catch(RemoteException e) {
@@ -440,11 +449,13 @@
         private final ISpellCheckerSessionListener mListener;
         private final String mSciId;
         private final String mLocale;
+        private final Bundle mBundle;
         public InternalServiceConnection(
-                String id, String locale, ISpellCheckerSessionListener listener) {
+                String id, String locale, ISpellCheckerSessionListener listener, Bundle bundle) {
             mSciId = id;
             mLocale = locale;
             mListener = listener;
+            mBundle = bundle;
         }
 
         @Override
@@ -473,14 +484,16 @@
         public final String mScLocale;
         private final SpellCheckerBindGroup mGroup;
         public final int mUid;
+        public final Bundle mBundle;
         public InternalDeathRecipient(SpellCheckerBindGroup group,
                 ITextServicesSessionListener tsListener, String scLocale,
-                ISpellCheckerSessionListener scListener, int uid) {
+                ISpellCheckerSessionListener scListener, int uid, Bundle bundle) {
             mTsListener = tsListener;
             mScListener = scListener;
             mScLocale = scLocale;
             mGroup = group;
             mUid = uid;
+            mBundle = bundle;
         }
 
         public boolean hasSpellCheckerListener(ISpellCheckerSessionListener listener) {
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 2460fd6..9765f2a 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -118,6 +118,10 @@
                         File changedFile = new File(WALLPAPER_DIR, path);
                         if (WALLPAPER_FILE.equals(changedFile)) {
                             notifyCallbacksLocked();
+                            if (mWallpaperComponent == null ||
+                                    mWallpaperComponent.equals(mImageWallpaperComponent)) {
+                                bindWallpaperComponentLocked(mWallpaperComponent, true);
+                            }
                         }
                     }
                 }
@@ -191,7 +195,7 @@
                     if (!mWallpaperUpdating && (mLastDiedTime+MIN_WALLPAPER_CRASH_TIME)
                                 > SystemClock.uptimeMillis()) {
                         Slog.w(TAG, "Reverting to built-in wallpaper!");
-                        bindWallpaperComponentLocked(null);
+                        bindWallpaperComponentLocked(null, true);
                     }
                 }
             }
@@ -220,7 +224,7 @@
                     mWallpaperUpdating = false;
                     ComponentName comp = mWallpaperComponent;
                     clearWallpaperComponentLocked();
-                    bindWallpaperComponentLocked(comp);
+                    bindWallpaperComponentLocked(comp, false);
                 }
             }
         }
@@ -312,11 +316,11 @@
         if (DEBUG) Slog.v(TAG, "systemReady");
         synchronized (mLock) {
             try {
-                bindWallpaperComponentLocked(mNextWallpaperComponent);
+                bindWallpaperComponentLocked(mNextWallpaperComponent, false);
             } catch (RuntimeException e) {
                 Slog.w(TAG, "Failure starting previous wallpaper", e);
                 try {
-                    bindWallpaperComponentLocked(null);
+                    bindWallpaperComponentLocked(null, false);
                 } catch (RuntimeException e2) {
                     Slog.w(TAG, "Failure starting default wallpaper", e2);
                     clearWallpaperComponentLocked();
@@ -339,7 +343,7 @@
         }
         final long ident = Binder.clearCallingIdentity();
         try {
-            bindWallpaperComponentLocked(null);
+            bindWallpaperComponentLocked(null, false);
         } catch (IllegalArgumentException e) {
             // This can happen if the default wallpaper component doesn't
             // exist.  This should be a system configuration problem, but
@@ -430,7 +434,7 @@
                 ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name);
                 if (pfd != null) {
                     // Bind the wallpaper to an ImageWallpaper
-                    bindWallpaperComponentLocked(mImageWallpaperComponent);
+                    bindWallpaperComponentLocked(mImageWallpaperComponent, false);
                     saveSettingsLocked();
                 }
                 return pfd;
@@ -459,28 +463,30 @@
         synchronized (mLock) {
             final long ident = Binder.clearCallingIdentity();
             try {
-                bindWallpaperComponentLocked(name);
+                bindWallpaperComponentLocked(name, false);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
         }
     }
     
-    void bindWallpaperComponentLocked(ComponentName componentName) {
+    void bindWallpaperComponentLocked(ComponentName componentName, boolean force) {
         if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName);
         
         // Has the component changed?
-        if (mWallpaperConnection != null) {
-            if (mWallpaperComponent == null) {
-                if (componentName == null) {
-                    if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: still using default");
-                    // Still using default wallpaper.
+        if (!force) {
+            if (mWallpaperConnection != null) {
+                if (mWallpaperComponent == null) {
+                    if (componentName == null) {
+                        if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: still using default");
+                        // Still using default wallpaper.
+                        return;
+                    }
+                } else if (mWallpaperComponent.equals(componentName)) {
+                    // Changing to same wallpaper.
+                    if (DEBUG) Slog.v(TAG, "same wallpaper");
                     return;
                 }
-            } else if (mWallpaperComponent.equals(componentName)) {
-                // Changing to same wallpaper.
-                if (DEBUG) Slog.v(TAG, "same wallpaper");
-                return;
             }
         }
         
@@ -599,7 +605,7 @@
         } catch (RemoteException e) {
             Slog.w(TAG, "Failed attaching wallpaper; clearing", e);
             if (!mWallpaperUpdating) {
-                bindWallpaperComponentLocked(null);
+                bindWallpaperComponentLocked(null, false);
             }
         }
     }
@@ -645,7 +651,8 @@
             out.attribute(null, "width", Integer.toString(mWidth));
             out.attribute(null, "height", Integer.toString(mHeight));
             out.attribute(null, "name", mName);
-            if (mWallpaperComponent != null) {
+            if (mWallpaperComponent != null &&
+                    !mWallpaperComponent.equals(mImageWallpaperComponent)) {
                 out.attribute(null, "component",
                         mWallpaperComponent.flattenToShortString());
             }
@@ -691,6 +698,10 @@
                         mNextWallpaperComponent = comp != null
                                 ? ComponentName.unflattenFromString(comp)
                                 : null;
+                        if (mNextWallpaperComponent == null ||
+                                "android".equals(mNextWallpaperComponent.getPackageName())) {
+                            mNextWallpaperComponent = mImageWallpaperComponent;
+                        }
                           
                         if (DEBUG) {
                             Slog.v(TAG, "mWidth:" + mWidth);
@@ -749,12 +760,12 @@
             if (mNextWallpaperComponent != null && 
                     !mNextWallpaperComponent.equals(mImageWallpaperComponent)) {
                 try {
-                    bindWallpaperComponentLocked(mNextWallpaperComponent);
+                    bindWallpaperComponentLocked(mNextWallpaperComponent, false);
                 } catch (IllegalArgumentException e) {
                     // No such live wallpaper or other failure; fall back to the default
                     // live wallpaper (since the profile being restored indicated that the
                     // user had selected a live rather than static one).
-                    bindWallpaperComponentLocked(null);
+                    bindWallpaperComponentLocked(null, false);
                 }
                 success = true;
             } else {
@@ -769,7 +780,7 @@
                 }
                 if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success);
                 if (success) {
-                    bindWallpaperComponentLocked(mImageWallpaperComponent);
+                    bindWallpaperComponentLocked(null, false);
                 }
             }
         }
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index f9f63b1..a80a2b8 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -289,6 +289,10 @@
                     mWifiStateMachine.startWps(msg.replyTo, (WpsConfiguration)msg.obj);
                     break;
                 }
+                case WifiManager.CMD_DISABLE_NETWORK: {
+                    mWifiStateMachine.disableNetwork(msg.replyTo, msg.arg1, msg.arg2);
+                    break;
+                }
                 default: {
                     Slog.d(TAG, "WifiServicehandler.handleMessage ignoring msg=" + msg);
                     break;
@@ -1592,7 +1596,10 @@
                 for (int i = scanResults.size() - 1; i >= 0; i--) {
                     ScanResult scanResult = scanResults.get(i);
 
-                    if (TextUtils.isEmpty(scanResult.capabilities)) {
+                    //A capability of [ESS] represents an open access point
+                    //that is available for an STA to connect
+                    if (scanResult.capabilities != null &&
+                            scanResult.capabilities.equals("[ESS]")) {
                         numOpenNetworks++;
                     }
                 }
diff --git a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 8ba0a0b..769cb6a 100644
--- a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -56,6 +56,11 @@
          * @param policyFlags The policy flags associated with the event.
          */
         public void clear(MotionEvent event, int policyFlags);
+
+        /**
+         * Requests that the explorer clears its internal state.
+         */
+        public void clear();
     }
 
     private TouchExplorer mTouchExplorer;
@@ -71,6 +76,7 @@
         if (DEBUG) {
             Slog.d(TAG, "Accessibility input filter installed.");
         }
+        mTouchExplorer = new TouchExplorer(this, mContext);
         super.onInstalled();
     }
 
@@ -79,6 +85,7 @@
         if (DEBUG) {
             Slog.d(TAG, "Accessibility input filter uninstalled.");
         }
+        mTouchExplorer.clear();
         super.onUninstalled();
     }
 
@@ -93,11 +100,7 @@
             int deviceId = event.getDeviceId();
             if (mTouchscreenSourceDeviceId != deviceId) {
                 mTouchscreenSourceDeviceId = deviceId;
-                if (mTouchExplorer != null) {
-                    mTouchExplorer.clear(motionEvent, policyFlags);
-                } else {
-                    mTouchExplorer = new TouchExplorer(this, mContext);
-                }
+                mTouchExplorer.clear(motionEvent, policyFlags);
             }
             if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) != 0) {
                 mTouchExplorer.onMotionEvent(motionEvent, policyFlags);
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index 0ad58d0..4ad2916 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -313,7 +313,7 @@
                             if (moveDelta > mTouchExplorationTapSlop) {
                                 mLastTouchExploreEvent = null;
                                 mPerformLongPressDelayed.remove();
-                               break;
+                                break;
                             }
                         }
                     } break;
@@ -388,6 +388,11 @@
                             mTouchExploreGestureInProgress = false;
                             mLastTouchExploreEvent = MotionEvent.obtain(event);
                             sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END);
+                            final int lastAction = mPointerTracker.getLastInjectedHoverAction();
+                            if (lastAction != MotionEvent.ACTION_HOVER_EXIT) {
+                                sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT,
+                                        pointerIdBits, policyFlags);
+                            }
                             break;
                         }
 
@@ -853,8 +858,9 @@
     /**
      * Clears the internal state of this explorer.
      */
-    private void clear() {
+    public void clear() {
         mSendHoverDelayed.remove();
+        mPerformLongPressDelayed.remove();
         mPointerTracker.clear();
         mLastTouchExploreEvent = null;
         mCurrentState = STATE_TOUCH_EXPLORING;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 14c6306..d3e12f7 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -248,135 +248,9 @@
     // How long we wait until we timeout on key dispatching.
     static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
 
-    // The minimum time we allow between crashes, for us to consider this
-    // application to be bad and stop and its services and reject broadcasts.
-    static final int MIN_CRASH_INTERVAL = 60*1000;
-
     // How long we wait until we timeout on key dispatching during instrumentation.
     static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
 
-    // OOM adjustments for processes in various states:
-
-    // This is a process without anything currently running in it.  Definitely
-    // the first to go! Value set in system/rootdir/init.rc on startup.
-    // This value is initalized in the constructor, careful when refering to
-    // this static variable externally.
-    static final int EMPTY_APP_ADJ;
-
-    // This is a process only hosting activities that are not visible,
-    // so it can be killed without any disruption. Value set in
-    // system/rootdir/init.rc on startup.
-    static final int HIDDEN_APP_MAX_ADJ;
-    static int HIDDEN_APP_MIN_ADJ;
-
-    // This is a process holding the home application -- we want to try
-    // avoiding killing it, even if it would normally be in the background,
-    // because the user interacts with it so much.
-    static final int HOME_APP_ADJ;
-
-    // This is a process currently hosting a backup operation.  Killing it
-    // is not entirely fatal but is generally a bad idea.
-    static final int BACKUP_APP_ADJ;
-
-    // This is a process holding a secondary server -- killing it will not
-    // have much of an impact as far as the user is concerned. Value set in
-    // system/rootdir/init.rc on startup.
-    static final int SECONDARY_SERVER_ADJ;
-
-    // This is a process with a heavy-weight application.  It is in the
-    // background, but we want to try to avoid killing it.  Value set in
-    // system/rootdir/init.rc on startup.
-    static final int HEAVY_WEIGHT_APP_ADJ;
-
-    // This is a process only hosting components that are perceptible to the
-    // user, and we really want to avoid killing them, but they are not
-    // immediately visible. An example is background music playback.  Value set in
-    // system/rootdir/init.rc on startup.
-    static final int PERCEPTIBLE_APP_ADJ;
-
-    // This is a process only hosting activities that are visible to the
-    // user, so we'd prefer they don't disappear. Value set in
-    // system/rootdir/init.rc on startup.
-    static final int VISIBLE_APP_ADJ;
-
-    // This is the process running the current foreground app.  We'd really
-    // rather not kill it! Value set in system/rootdir/init.rc on startup.
-    static final int FOREGROUND_APP_ADJ;
-
-    // This is a process running a core server, such as telephony.  Definitely
-    // don't want to kill it, but doing so is not completely fatal.
-    static final int CORE_SERVER_ADJ = -12;
-
-    // The system process runs at the default adjustment.
-    static final int SYSTEM_ADJ = -16;
-
-    // Memory pages are 4K.
-    static final int PAGE_SIZE = 4*1024;
-    
-    // Corresponding memory levels for above adjustments.
-    static final int EMPTY_APP_MEM;
-    static final int HIDDEN_APP_MEM;
-    static final int HOME_APP_MEM;
-    static final int BACKUP_APP_MEM;
-    static final int SECONDARY_SERVER_MEM;
-    static final int HEAVY_WEIGHT_APP_MEM;
-    static final int PERCEPTIBLE_APP_MEM;
-    static final int VISIBLE_APP_MEM;
-    static final int FOREGROUND_APP_MEM;
-
-    // The minimum number of hidden apps we want to be able to keep around,
-    // without empty apps being able to push them out of memory.
-    static final int MIN_HIDDEN_APPS = 2;
-    
-    // The maximum number of hidden processes we will keep around before
-    // killing them; this is just a control to not let us go too crazy with
-    // keeping around processes on devices with large amounts of RAM.
-    static final int MAX_HIDDEN_APPS = 15;
-    
-    // We put empty content processes after any hidden processes that have
-    // been idle for less than 15 seconds.
-    static final long CONTENT_APP_IDLE_OFFSET = 15*1000;
-    
-    // We put empty content processes after any hidden processes that have
-    // been idle for less than 120 seconds.
-    static final long EMPTY_APP_IDLE_OFFSET = 120*1000;
-    
-    static int getIntProp(String name, boolean allowZero) {
-        String str = SystemProperties.get(name);
-        if (str == null) {
-            throw new IllegalArgumentException("Property not defined: " + name);
-        }
-        int val = Integer.valueOf(str);
-        if (val == 0 && !allowZero) {
-            throw new IllegalArgumentException("Property must not be zero: " + name);
-        }
-        return val;
-    }
-    
-    static {
-        // These values are set in system/rootdir/init.rc on startup.
-        FOREGROUND_APP_ADJ = getIntProp("ro.FOREGROUND_APP_ADJ", true);
-        VISIBLE_APP_ADJ = getIntProp("ro.VISIBLE_APP_ADJ", true);
-        PERCEPTIBLE_APP_ADJ = getIntProp("ro.PERCEPTIBLE_APP_ADJ", true);
-        HEAVY_WEIGHT_APP_ADJ = getIntProp("ro.HEAVY_WEIGHT_APP_ADJ", true);
-        SECONDARY_SERVER_ADJ = getIntProp("ro.SECONDARY_SERVER_ADJ", true);
-        BACKUP_APP_ADJ = getIntProp("ro.BACKUP_APP_ADJ", true);
-        HOME_APP_ADJ = getIntProp("ro.HOME_APP_ADJ", true);
-        HIDDEN_APP_MIN_ADJ = getIntProp("ro.HIDDEN_APP_MIN_ADJ", true);
-        EMPTY_APP_ADJ = getIntProp("ro.EMPTY_APP_ADJ", true);
-        // These days we use the last empty slot for hidden apps as well.
-        HIDDEN_APP_MAX_ADJ = EMPTY_APP_ADJ;
-        FOREGROUND_APP_MEM = getIntProp("ro.FOREGROUND_APP_MEM", false)*PAGE_SIZE;
-        VISIBLE_APP_MEM = getIntProp("ro.VISIBLE_APP_MEM", false)*PAGE_SIZE;
-        PERCEPTIBLE_APP_MEM = getIntProp("ro.PERCEPTIBLE_APP_MEM", false)*PAGE_SIZE;
-        HEAVY_WEIGHT_APP_MEM = getIntProp("ro.HEAVY_WEIGHT_APP_MEM", false)*PAGE_SIZE;
-        SECONDARY_SERVER_MEM = getIntProp("ro.SECONDARY_SERVER_MEM", false)*PAGE_SIZE;
-        BACKUP_APP_MEM = getIntProp("ro.BACKUP_APP_MEM", false)*PAGE_SIZE;
-        HOME_APP_MEM = getIntProp("ro.HOME_APP_MEM", false)*PAGE_SIZE;
-        HIDDEN_APP_MEM = getIntProp("ro.HIDDEN_APP_MEM", false)*PAGE_SIZE;
-        EMPTY_APP_MEM = getIntProp("ro.EMPTY_APP_MEM", false)*PAGE_SIZE;
-    }
-    
     static final int MY_PID = Process.myPid();
     
     static final String[] EMPTY_STRING_ARRAY = new String[0];
@@ -437,6 +311,11 @@
     final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>();
 
     /**
+     * Process management.
+     */
+    final ProcessList mProcessList = new ProcessList();
+
+    /**
      * All of the applications we currently have running organized by name.
      * The keys are strings of the application package name (as
      * returned by the package manager), and the keys are ApplicationRecord
@@ -900,7 +779,7 @@
      */
     boolean mBooted = false;
 
-    int mProcessLimit = MAX_HIDDEN_APPS;
+    int mProcessLimit = ProcessList.MAX_HIDDEN_APPS;
     int mProcessLimitOverride = -1;
 
     WindowManagerService mWindowManager;
@@ -1327,7 +1206,7 @@
                         info.processName);
                 app.persistent = true;
                 app.pid = MY_PID;
-                app.maxAdj = SYSTEM_ADJ;
+                app.maxAdj = ProcessList.SYSTEM_ADJ;
                 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
                 synchronized (mSelf.mPidsSelfLocked) {
                     mSelf.mPidsSelfLocked.put(app.pid, app);
@@ -1702,23 +1581,23 @@
         } else if (app.pubProviders.size() > 0) {
             // If this process contains content providers, we want to keep
             // it a little more strongly.
-            app.lruWeight = app.lastActivityTime - CONTENT_APP_IDLE_OFFSET;
+            app.lruWeight = app.lastActivityTime - ProcessList.CONTENT_APP_IDLE_OFFSET;
             // Also don't let it kick out the first few "real" hidden processes.
-            skipTop = MIN_HIDDEN_APPS;
+            skipTop = ProcessList.MIN_HIDDEN_APPS;
         } else {
             // If this process doesn't have activities, we less strongly
             // want to keep it around, and generally want to avoid getting
             // in front of any very recently used activities.
-            app.lruWeight = app.lastActivityTime - EMPTY_APP_IDLE_OFFSET;
+            app.lruWeight = app.lastActivityTime - ProcessList.EMPTY_APP_IDLE_OFFSET;
             // Also don't let it kick out the first few "real" hidden processes.
-            skipTop = MIN_HIDDEN_APPS;
+            skipTop = ProcessList.MIN_HIDDEN_APPS;
         }
         
         while (i >= 0) {
             ProcessRecord p = mLruProcesses.get(i);
             // If this app shouldn't be in front of the first N background
             // apps, then skip over that many that are currently hidden.
-            if (skipTop > 0 && p.setAdj >= HIDDEN_APP_MIN_ADJ) {
+            if (skipTop > 0 && p.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
                 skipTop--;
             }
             if (p.lruWeight <= app.lruWeight || i < bestPos) {
@@ -2800,7 +2679,7 @@
                 boolean haveBg = false;
                 for (int i=mLruProcesses.size()-1; i>=0; i--) {
                     ProcessRecord rec = mLruProcesses.get(i);
-                    if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
+                    if (rec.thread != null && rec.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
                         haveBg = true;
                         break;
                     }
@@ -2817,7 +2696,7 @@
                             // The low memory report is overriding any current
                             // state for a GC request.  Make sure to do
                             // heavy/important/visible/foreground processes first.
-                            if (rec.setAdj <= HEAVY_WEIGHT_APP_ADJ) {
+                            if (rec.setAdj <= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
                                 rec.lastRequestedGc = 0;
                             } else {
                                 rec.lastRequestedGc = rec.lastLowMemory;
@@ -3195,7 +3074,7 @@
                     return;
                 }
                 killPackageProcessesLocked(packageName, pkgUid,
-                        SECONDARY_SERVER_ADJ, false, true, true);
+                        ProcessList.SECONDARY_SERVER_ADJ, false, true, true);
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
@@ -3317,6 +3196,14 @@
         return infos;
     }
 
+    public long[] getProcessPss(int[] pids) throws RemoteException {
+        long[] pss = new long[pids.length];
+        for (int i=pids.length-1; i>=0; i--) {
+            pss[i] = Debug.getPss(pids[i]);
+        }
+        return pss;
+    }
+
     public void killApplicationProcess(String processName, int uid) {
         if (processName == null) {
             return;
@@ -4159,7 +4046,7 @@
         enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
                 "setProcessLimit()");
         synchronized (this) {
-            mProcessLimit = max < 0 ? MAX_HIDDEN_APPS : max;
+            mProcessLimit = max < 0 ? ProcessList.MAX_HIDDEN_APPS : max;
             mProcessLimitOverride = max;
         }
         trimApplications();
@@ -4908,10 +4795,18 @@
     }
 
     public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
+        final long homeAppMem = mProcessList.getMemLevel(ProcessList.HOME_APP_ADJ);
+        final long hiddenAppMem = mProcessList.getMemLevel(ProcessList.HIDDEN_APP_MIN_ADJ);
         outInfo.availMem = Process.getFreeMemory();
-        outInfo.threshold = HOME_APP_MEM;
-        outInfo.lowMemory = outInfo.availMem <
-                (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
+        outInfo.threshold = homeAppMem;
+        outInfo.lowMemory = outInfo.availMem < (homeAppMem + ((hiddenAppMem-homeAppMem)/2));
+        outInfo.hiddenAppThreshold = hiddenAppMem;
+        outInfo.secondaryServerThreshold = mProcessList.getMemLevel(
+                ProcessList.SECONDARY_SERVER_ADJ);
+        outInfo.visibleAppThreshold = mProcessList.getMemLevel(
+                ProcessList.VISIBLE_APP_ADJ);
+        outInfo.foregroundAppThreshold = mProcessList.getMemLevel(
+                ProcessList.FOREGROUND_APP_ADJ);
     }
     
     // =========================================================
@@ -5633,7 +5528,7 @@
                         r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
                     }
                     cpr.clients.add(r);
-                    if (cpr.app != null && r.setAdj <= PERCEPTIBLE_APP_ADJ) {
+                    if (cpr.app != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
                         // If this is a perceptible app accessing the provider,
                         // make sure to count it as being accessed and thus
                         // back up on the LRU list.  This is good because
@@ -6023,7 +5918,7 @@
         if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
                 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
             app.persistent = true;
-            app.maxAdj = CORE_SERVER_ADJ;
+            app.maxAdj = ProcessList.CORE_SERVER_ADJ;
         }
         if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
             mPersistentStartingProcesses.add(app);
@@ -6397,14 +6292,14 @@
             
             // If the worst oom_adj is somewhere in the hidden proc LRU range,
             // then constrain it so we will kill all hidden procs.
-            if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
-                worstType = HIDDEN_APP_MIN_ADJ;
+            if (worstType < ProcessList.EMPTY_APP_ADJ && worstType > ProcessList.HIDDEN_APP_MIN_ADJ) {
+                worstType = ProcessList.HIDDEN_APP_MIN_ADJ;
             }
 
             // If this is not a secure call, don't let it kill processes that
             // are important.
-            if (!secure && worstType < SECONDARY_SERVER_ADJ) {
-                worstType = SECONDARY_SERVER_ADJ;
+            if (!secure && worstType < ProcessList.SECONDARY_SERVER_ADJ) {
+                worstType = ProcessList.SECONDARY_SERVER_ADJ;
             }
 
             Slog.w(TAG, "Killing processes " + reason + " at adjustment " + worstType);
@@ -6818,7 +6713,7 @@
 
         Long crashTime = mProcessCrashTimes.get(app.info.processName,
                 app.info.uid);
-        if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
+        if (crashTime != null && now < crashTime+ProcessList.MIN_CRASH_INTERVAL) {
             // This process loses!
             Slog.w(TAG, "Process " + app.info.processName
                     + " has crashed too many times: killing!");
@@ -7547,21 +7442,21 @@
                         currApp.flags |= ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT;
                     }
                     int adj = app.curAdj;
-                    if (adj >= EMPTY_APP_ADJ) {
+                    if (adj >= ProcessList.EMPTY_APP_ADJ) {
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
-                    } else if (adj >= HIDDEN_APP_MIN_ADJ) {
+                    } else if (adj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
-                        currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
-                    } else if (adj >= HOME_APP_ADJ) {
+                        currApp.lru = adj - ProcessList.HIDDEN_APP_MIN_ADJ + 1;
+                    } else if (adj >= ProcessList.HOME_APP_ADJ) {
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
                         currApp.lru = 0;
-                    } else if (adj >= SECONDARY_SERVER_ADJ) {
+                    } else if (adj >= ProcessList.SECONDARY_SERVER_ADJ) {
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
-                    } else if (adj >= HEAVY_WEIGHT_APP_ADJ) {
+                    } else if (adj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE;
-                    } else if (adj >= PERCEPTIBLE_APP_ADJ) {
+                    } else if (adj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE;
-                    } else if (adj >= VISIBLE_APP_ADJ) {
+                    } else if (adj >= ProcessList.VISIBLE_APP_ADJ) {
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
                     } else {
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
@@ -8068,17 +7963,17 @@
             if (needSep) pw.println(" ");
             needSep = true;
             pw.println("  OOM levels:");
-            pw.print("    SYSTEM_ADJ: "); pw.println(SYSTEM_ADJ);
-            pw.print("    CORE_SERVER_ADJ: "); pw.println(CORE_SERVER_ADJ);
-            pw.print("    FOREGROUND_APP_ADJ: "); pw.println(FOREGROUND_APP_ADJ);
-            pw.print("    VISIBLE_APP_ADJ: "); pw.println(VISIBLE_APP_ADJ);
-            pw.print("    PERCEPTIBLE_APP_ADJ: "); pw.println(PERCEPTIBLE_APP_ADJ);
-            pw.print("    HEAVY_WEIGHT_APP_ADJ: "); pw.println(HEAVY_WEIGHT_APP_ADJ);
-            pw.print("    BACKUP_APP_ADJ: "); pw.println(BACKUP_APP_ADJ);
-            pw.print("    SECONDARY_SERVER_ADJ: "); pw.println(SECONDARY_SERVER_ADJ);
-            pw.print("    HOME_APP_ADJ: "); pw.println(HOME_APP_ADJ);
-            pw.print("    HIDDEN_APP_MIN_ADJ: "); pw.println(HIDDEN_APP_MIN_ADJ);
-            pw.print("    EMPTY_APP_ADJ: "); pw.println(EMPTY_APP_ADJ);
+            pw.print("    SYSTEM_ADJ: "); pw.println(ProcessList.SYSTEM_ADJ);
+            pw.print("    CORE_SERVER_ADJ: "); pw.println(ProcessList.CORE_SERVER_ADJ);
+            pw.print("    FOREGROUND_APP_ADJ: "); pw.println(ProcessList.FOREGROUND_APP_ADJ);
+            pw.print("    VISIBLE_APP_ADJ: "); pw.println(ProcessList.VISIBLE_APP_ADJ);
+            pw.print("    PERCEPTIBLE_APP_ADJ: "); pw.println(ProcessList.PERCEPTIBLE_APP_ADJ);
+            pw.print("    HEAVY_WEIGHT_APP_ADJ: "); pw.println(ProcessList.HEAVY_WEIGHT_APP_ADJ);
+            pw.print("    BACKUP_APP_ADJ: "); pw.println(ProcessList.BACKUP_APP_ADJ);
+            pw.print("    SECONDARY_SERVER_ADJ: "); pw.println(ProcessList.SECONDARY_SERVER_ADJ);
+            pw.print("    HOME_APP_ADJ: "); pw.println(ProcessList.HOME_APP_ADJ);
+            pw.print("    HIDDEN_APP_MIN_ADJ: "); pw.println(ProcessList.HIDDEN_APP_MIN_ADJ);
+            pw.print("    EMPTY_APP_ADJ: "); pw.println(ProcessList.EMPTY_APP_ADJ);
 
             if (needSep) pw.println(" ");
             needSep = true;
@@ -8746,28 +8641,28 @@
         for (int i=N; i>=0; i--) {
             ProcessRecord r = list.get(i);
             String oomAdj;
-            if (r.setAdj >= EMPTY_APP_ADJ) {
-                oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ);
-            } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
-                oomAdj = buildOomTag("bak", "  ", r.setAdj, HIDDEN_APP_MIN_ADJ);
-            } else if (r.setAdj >= HOME_APP_ADJ) {
-                oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ);
-            } else if (r.setAdj >= SECONDARY_SERVER_ADJ) {
-                oomAdj = buildOomTag("svc", "  ", r.setAdj, SECONDARY_SERVER_ADJ);
-            } else if (r.setAdj >= BACKUP_APP_ADJ) {
-                oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ);
-            } else if (r.setAdj >= HEAVY_WEIGHT_APP_ADJ) {
-                oomAdj = buildOomTag("hvy  ", null, r.setAdj, HEAVY_WEIGHT_APP_ADJ);
-            } else if (r.setAdj >= PERCEPTIBLE_APP_ADJ) {
-                oomAdj = buildOomTag("prcp ", null, r.setAdj, PERCEPTIBLE_APP_ADJ);
-            } else if (r.setAdj >= VISIBLE_APP_ADJ) {
-                oomAdj = buildOomTag("vis  ", null, r.setAdj, VISIBLE_APP_ADJ);
-            } else if (r.setAdj >= FOREGROUND_APP_ADJ) {
-                oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ);
-            } else if (r.setAdj >= CORE_SERVER_ADJ) {
-                oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ);
-            } else if (r.setAdj >= SYSTEM_ADJ) {
-                oomAdj = buildOomTag("sys  ", null, r.setAdj, SYSTEM_ADJ);
+            if (r.setAdj >= ProcessList.EMPTY_APP_ADJ) {
+                oomAdj = buildOomTag("empty", null, r.setAdj, ProcessList.EMPTY_APP_ADJ);
+            } else if (r.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
+                oomAdj = buildOomTag("bak", "  ", r.setAdj, ProcessList.HIDDEN_APP_MIN_ADJ);
+            } else if (r.setAdj >= ProcessList.HOME_APP_ADJ) {
+                oomAdj = buildOomTag("home ", null, r.setAdj, ProcessList.HOME_APP_ADJ);
+            } else if (r.setAdj >= ProcessList.SECONDARY_SERVER_ADJ) {
+                oomAdj = buildOomTag("svc", "  ", r.setAdj, ProcessList.SECONDARY_SERVER_ADJ);
+            } else if (r.setAdj >= ProcessList.BACKUP_APP_ADJ) {
+                oomAdj = buildOomTag("bckup", null, r.setAdj, ProcessList.BACKUP_APP_ADJ);
+            } else if (r.setAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+                oomAdj = buildOomTag("hvy  ", null, r.setAdj, ProcessList.HEAVY_WEIGHT_APP_ADJ);
+            } else if (r.setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
+                oomAdj = buildOomTag("prcp ", null, r.setAdj, ProcessList.PERCEPTIBLE_APP_ADJ);
+            } else if (r.setAdj >= ProcessList.VISIBLE_APP_ADJ) {
+                oomAdj = buildOomTag("vis  ", null, r.setAdj, ProcessList.VISIBLE_APP_ADJ);
+            } else if (r.setAdj >= ProcessList.FOREGROUND_APP_ADJ) {
+                oomAdj = buildOomTag("fore ", null, r.setAdj, ProcessList.FOREGROUND_APP_ADJ);
+            } else if (r.setAdj >= ProcessList.CORE_SERVER_ADJ) {
+                oomAdj = buildOomTag("core ", null, r.setAdj, ProcessList.CORE_SERVER_ADJ);
+            } else if (r.setAdj >= ProcessList.SYSTEM_ADJ) {
+                oomAdj = buildOomTag("sys  ", null, r.setAdj, ProcessList.SYSTEM_ADJ);
             } else {
                 oomAdj = Integer.toString(r.setAdj);
             }
@@ -8868,15 +8763,15 @@
         }
     }
 
-    ArrayList<ProcessRecord> collectProcesses(PrintWriter pw, String[] args) {
+    ArrayList<ProcessRecord> collectProcesses(PrintWriter pw, int start, String[] args) {
         ArrayList<ProcessRecord> procs;
         synchronized (this) {
-            if (args != null && args.length > 0
-                    && args[0].charAt(0) != '-') {
+            if (args != null && args.length > start
+                    && args[start].charAt(0) != '-') {
                 procs = new ArrayList<ProcessRecord>();
                 int pid = -1;
                 try {
-                    pid = Integer.parseInt(args[0]);
+                    pid = Integer.parseInt(args[start]);
                 } catch (NumberFormatException e) {
 
                 }
@@ -8884,12 +8779,12 @@
                     ProcessRecord proc = mLruProcesses.get(i);
                     if (proc.pid == pid) {
                         procs.add(proc);
-                    } else if (proc.processName.equals(args[0])) {
+                    } else if (proc.processName.equals(args[start])) {
                         procs.add(proc);
                     }
                 }
                 if (procs.size() <= 0) {
-                    pw.println("No process found for: " + args[0]);
+                    pw.println("No process found for: " + args[start]);
                     return null;
                 }
             } else {
@@ -8901,7 +8796,7 @@
 
     final void dumpGraphicsHardwareUsage(FileDescriptor fd,
             PrintWriter pw, String[] args) {
-        ArrayList<ProcessRecord> procs = collectProcesses(pw, args);
+        ArrayList<ProcessRecord> procs = collectProcesses(pw, 0, args);
         if (procs == null) {
             return;
         }
@@ -8945,18 +8840,21 @@
         }
     }
 
-    final void dumpMemItems(PrintWriter pw, String prefix, ArrayList<MemItem> items) {
-        Collections.sort(items, new Comparator<MemItem>() {
-            @Override
-            public int compare(MemItem lhs, MemItem rhs) {
-                if (lhs.pss < rhs.pss) {
-                    return 1;
-                } else if (lhs.pss > rhs.pss) {
-                    return -1;
+    final void dumpMemItems(PrintWriter pw, String prefix, ArrayList<MemItem> items,
+            boolean sort) {
+        if (sort) {
+            Collections.sort(items, new Comparator<MemItem>() {
+                @Override
+                public int compare(MemItem lhs, MemItem rhs) {
+                    if (lhs.pss < rhs.pss) {
+                        return 1;
+                    } else if (lhs.pss > rhs.pss) {
+                        return -1;
+                    }
+                    return 0;
                 }
-                return 0;
-            }
-        });
+            });
+        }
 
         for (int i=0; i<items.size(); i++) {
             MemItem mi = items.get(i);
@@ -8966,7 +8864,29 @@
 
     final void dumpApplicationMemoryUsage(FileDescriptor fd,
             PrintWriter pw, String prefix, String[] args) {
-        ArrayList<ProcessRecord> procs = collectProcesses(pw, args);
+        boolean dumpAll = false;
+        
+        int opti = 0;
+        while (opti < args.length) {
+            String opt = args[opti];
+            if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
+                break;
+            }
+            opti++;
+            if ("-a".equals(opt)) {
+                dumpAll = true;
+            } else if ("-h".equals(opt)) {
+                pw.println("meminfo dump options: [-a] [process]");
+                pw.println("  -a: include all available information for each process.");
+                pw.println("If [process] is specified it can be the name or ");
+                pw.println("pid of a specific process to dump.");
+                return;
+            } else {
+                pw.println("Unknown argument: " + opt + "; use -h for help");
+            }
+        }
+        
+        ArrayList<ProcessRecord> procs = collectProcesses(pw, opti, args);
         if (procs == null) {
             return;
         }
@@ -8974,7 +8894,11 @@
         final boolean isCheckinRequest = scanArgs(args, "--checkin");
         long uptime = SystemClock.uptimeMillis();
         long realtime = SystemClock.elapsedRealtime();
-        
+
+        if (procs.size() == 1 || isCheckinRequest) {
+            dumpAll = true;
+        }
+
         if (isCheckinRequest) {
             // short checkin version
             pw.println(uptime + "," + realtime);
@@ -8984,29 +8908,53 @@
             pw.println("Uptime: " + uptime + " Realtime: " + realtime);
         }
 
+        String[] innerArgs = new String[args.length-opti];
+        System.arraycopy(args, opti, innerArgs, 0, args.length-opti);
+
         ArrayList<MemItem> procMems = new ArrayList<MemItem>();
         long nativePss=0, dalvikPss=0, otherPss=0;
         long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
 
+        final int[] oomAdj = new int[] {
+            ProcessList.SYSTEM_ADJ, ProcessList.CORE_SERVER_ADJ, ProcessList.FOREGROUND_APP_ADJ,
+            ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
+            ProcessList.BACKUP_APP_ADJ, ProcessList.SECONDARY_SERVER_ADJ, ProcessList.HOME_APP_ADJ, ProcessList.EMPTY_APP_ADJ
+        };
+        final String[] oomLabel = new String[] {
+                "System", "Persistent", "Foreground",
+                "Visible", "Perceptible", "Heavy Weight",
+                "Backup", "Services", "Home", "Background"
+        };
+        long oomPss[] = new long[oomLabel.length];
+
+        long totalPss = 0;
+
         for (int i = procs.size() - 1 ; i >= 0 ; i--) {
             ProcessRecord r = procs.get(i);
             if (r.thread != null) {
-                if (!isCheckinRequest) {
+                if (!isCheckinRequest && dumpAll) {
                     pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
                     pw.flush();
                 }
                 Debug.MemoryInfo mi = null;
-                try {
-                    mi = r.thread.dumpMemInfo(fd, args);
-                } catch (RemoteException e) {
-                    if (!isCheckinRequest) {
-                        pw.println("Got RemoteException!");
-                        pw.flush();
+                if (dumpAll) {
+                    try {
+                        mi = r.thread.dumpMemInfo(fd, isCheckinRequest, dumpAll, innerArgs);
+                    } catch (RemoteException e) {
+                        if (!isCheckinRequest) {
+                            pw.println("Got RemoteException!");
+                            pw.flush();
+                        }
                     }
+                } else {
+                    mi = new Debug.MemoryInfo();
+                    Debug.getMemoryInfo(r.pid, mi);
                 }
+
                 if (!isCheckinRequest && mi != null) {
-                    procMems.add(new MemItem(r.processName + " (pid " + r.pid + ")",
-                            mi.getTotalPss()));
+                    long myTotalPss = mi.getTotalPss();
+                    totalPss += myTotalPss;
+                    procMems.add(new MemItem(r.processName + " (pid " + r.pid + ")", myTotalPss));
 
                     nativePss += mi.nativePss;
                     dalvikPss += mi.dalvikPss;
@@ -9016,6 +8964,13 @@
                         miscPss[j] += mem;
                         otherPss -= mem;
                     }
+
+                    for (int oomIndex=0; oomIndex<oomPss.length; oomIndex++) {
+                        if (r.setAdj <= oomAdj[oomIndex] || oomIndex == (oomPss.length-1)) {
+                            oomPss[oomIndex] += myTotalPss;
+                            break;
+                        }
+                    }
                 }
             }
         }
@@ -9030,12 +8985,24 @@
                 catMems.add(new MemItem(Debug.MemoryInfo.getOtherLabel(j), miscPss[j]));
             }
 
+            ArrayList<MemItem> oomMems = new ArrayList<MemItem>();
+            for (int j=0; j<oomPss.length; j++) {
+                if (oomPss[j] != 0) {
+                    oomMems.add(new MemItem(oomLabel[j], oomPss[j]));
+                }
+            }
+
             pw.println();
             pw.println("Total PSS by process:");
-            dumpMemItems(pw, "  ", procMems);
+            dumpMemItems(pw, "  ", procMems, true);
+            pw.println();
+            pw.println("Total PSS by OOM adjustment:");
+            dumpMemItems(pw, "  ", oomMems, false);
             pw.println();
             pw.println("Total PSS by category:");
-            dumpMemItems(pw, "  ", catMems);
+            dumpMemItems(pw, "  ", catMems, true);
+            pw.println();
+            pw.print("Total PSS: "); pw.print(totalPss); pw.println(" Kb");
         }
     }
 
@@ -12458,7 +12425,11 @@
                 // sentinel: fetch the current configuration from the window manager
                 values = mWindowManager.computeNewConfiguration();
             }
-            
+
+            if (mWindowManager != null) {
+                mProcessList.applyDisplaySize(mWindowManager);
+            }
+
             final long origId = Binder.clearCallingIdentity();
             if (values != null) {
                 Settings.System.clearConfiguration(values);
@@ -12608,7 +12579,7 @@
         if (app.thread == null) {
             app.adjSeq = mAdjSeq;
             app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
-            return (app.curAdj=EMPTY_APP_ADJ);
+            return (app.curAdj=ProcessList.EMPTY_APP_ADJ);
         }
 
         app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
@@ -12619,7 +12590,7 @@
 
         final int activitiesSize = app.activities.size();
 
-        if (app.maxAdj <= FOREGROUND_APP_ADJ) {
+        if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
             // The max adjustment doesn't allow this app to be anything
             // below foreground, so it is not worth doing work for it.
             app.adjType = "fixed";
@@ -12659,26 +12630,26 @@
         int schedGroup;
         if (app == TOP_APP) {
             // The last app on the list is the foreground app.
-            adj = FOREGROUND_APP_ADJ;
+            adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_DEFAULT;
             app.adjType = "top-activity";
             app.foregroundActivities = true;
         } else if (app.instrumentationClass != null) {
             // Don't want to kill running instrumentation.
-            adj = FOREGROUND_APP_ADJ;
+            adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_DEFAULT;
             app.adjType = "instrumentation";
         } else if (app.curReceiver != null ||
                 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
             // An app that is currently receiving a broadcast also
             // counts as being in the foreground.
-            adj = FOREGROUND_APP_ADJ;
+            adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_DEFAULT;
             app.adjType = "broadcast";
         } else if (app.executingServices.size() > 0) {
             // An app that is currently executing a service callback also
             // counts as being in the foreground.
-            adj = FOREGROUND_APP_ADJ;
+            adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_DEFAULT;
             app.adjType = "exec-service";
         } else if (activitiesSize > 0) {
@@ -12704,8 +12675,8 @@
                 final ActivityRecord r = app.activities.get(j);
                 if (r.visible) {
                     // App has a visible activity; only upgrade adjustment.
-                    if (adj > VISIBLE_APP_ADJ) {
-                        adj = VISIBLE_APP_ADJ;
+                    if (adj > ProcessList.VISIBLE_APP_ADJ) {
+                        adj = ProcessList.VISIBLE_APP_ADJ;
                         app.adjType = "visible";
                     }
                     schedGroup = Process.THREAD_GROUP_DEFAULT;
@@ -12715,8 +12686,8 @@
                 } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED
                         || r.state == ActivityState.STOPPING) {
                     // Only upgrade adjustment.
-                    if (adj > PERCEPTIBLE_APP_ADJ) {
-                        adj = PERCEPTIBLE_APP_ADJ;
+                    if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+                        adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                         app.adjType = "stopping";
                     }
                     app.foregroundActivities = true;
@@ -12724,32 +12695,32 @@
             }
         }
 
-        if (adj > PERCEPTIBLE_APP_ADJ) {
+        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
             if (app.foregroundServices) {
                 // The user is aware of this app, so make it visible.
-                adj = PERCEPTIBLE_APP_ADJ;
+                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                 app.adjType = "foreground-service";
                 schedGroup = Process.THREAD_GROUP_DEFAULT;
             } else if (app.forcingToForeground != null) {
                 // The user is aware of this app, so make it visible.
-                adj = PERCEPTIBLE_APP_ADJ;
+                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                 app.adjType = "force-foreground";
                 app.adjSource = app.forcingToForeground;
                 schedGroup = Process.THREAD_GROUP_DEFAULT;
             }
         }
 
-        if (adj > HEAVY_WEIGHT_APP_ADJ && app == mHeavyWeightProcess) {
+        if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ && app == mHeavyWeightProcess) {
             // We don't want to kill the current heavy-weight process.
-            adj = HEAVY_WEIGHT_APP_ADJ;
+            adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
             app.adjType = "heavy";
         }
 
-        if (adj > HOME_APP_ADJ && app == mHomeProcess) {
+        if (adj > ProcessList.HOME_APP_ADJ && app == mHomeProcess) {
             // This process is hosting what we currently consider to be the
             // home app, so we don't want to let it go into the background.
-            adj = HOME_APP_ADJ;
+            adj = ProcessList.HOME_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
             app.adjType = "home";
         }
@@ -12765,21 +12736,21 @@
 
         if (mBackupTarget != null && app == mBackupTarget.app) {
             // If possible we want to avoid killing apps while they're being backed up
-            if (adj > BACKUP_APP_ADJ) {
+            if (adj > ProcessList.BACKUP_APP_ADJ) {
                 if (DEBUG_BACKUP) Slog.v(TAG, "oom BACKUP_APP_ADJ for " + app);
-                adj = BACKUP_APP_ADJ;
+                adj = ProcessList.BACKUP_APP_ADJ;
                 app.adjType = "backup";
                 app.hidden = false;
             }
         }
 
-        if (app.services.size() != 0 && (adj > FOREGROUND_APP_ADJ
+        if (app.services.size() != 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
             final long now = SystemClock.uptimeMillis();
             // This process is more important if the top activity is
             // bound to the service.
             Iterator<ServiceRecord> jt = app.services.iterator();
-            while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
+            while (jt.hasNext() && adj > ProcessList.FOREGROUND_APP_ADJ) {
                 ServiceRecord s = jt.next();
                 if (s.startRequested) {
                     if (app.hasShownUi) {
@@ -12787,7 +12758,7 @@
                         // go to the LRU list because it may be pretty heavy with
                         // UI stuff.  We'll tag it with a label just to help
                         // debug and understand what is going on.
-                        if (adj > SECONDARY_SERVER_ADJ) {
+                        if (adj > ProcessList.SECONDARY_SERVER_ADJ) {
                             app.adjType = "started-bg-ui-services";
                         }
                     } else {
@@ -12795,8 +12766,8 @@
                             // This service has seen some activity within
                             // recent memory, so we will keep its process ahead
                             // of the background processes.
-                            if (adj > SECONDARY_SERVER_ADJ) {
-                                adj = SECONDARY_SERVER_ADJ;
+                            if (adj > ProcessList.SECONDARY_SERVER_ADJ) {
+                                adj = ProcessList.SECONDARY_SERVER_ADJ;
                                 app.adjType = "started-services";
                                 app.hidden = false;
                             }
@@ -12804,7 +12775,7 @@
                         // If we have let the service slide into the background
                         // state, still have some text describing what it is doing
                         // even though the service no longer has an impact.
-                        if (adj > SECONDARY_SERVER_ADJ) {
+                        if (adj > ProcessList.SECONDARY_SERVER_ADJ) {
                             app.adjType = "started-bg-services";
                         }
                     }
@@ -12812,13 +12783,13 @@
                     // has said it is doing work.
                     app.keeping = true;
                 }
-                if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
+                if (s.connections.size() > 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                         || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
                     Iterator<ArrayList<ConnectionRecord>> kt
                             = s.connections.values().iterator();
-                    while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
+                    while (kt.hasNext() && adj > ProcessList.FOREGROUND_APP_ADJ) {
                         ArrayList<ConnectionRecord> clist = kt.next();
-                        for (int i=0; i<clist.size() && adj > FOREGROUND_APP_ADJ; i++) {
+                        for (int i=0; i<clist.size() && adj > ProcessList.FOREGROUND_APP_ADJ; i++) {
                             // XXX should compute this based on the max of
                             // all connected clients.
                             ConnectionRecord cr = clist.get(i);
@@ -12831,10 +12802,10 @@
                                 int clientAdj = adj;
                                 int myHiddenAdj = hiddenAdj;
                                 if (myHiddenAdj > client.hiddenAdj) {
-                                    if (client.hiddenAdj >= VISIBLE_APP_ADJ) {
+                                    if (client.hiddenAdj >= ProcessList.VISIBLE_APP_ADJ) {
                                         myHiddenAdj = client.hiddenAdj;
                                     } else {
-                                        myHiddenAdj = VISIBLE_APP_ADJ;
+                                        myHiddenAdj = ProcessList.VISIBLE_APP_ADJ;
                                     }
                                 }
                                 clientAdj = computeOomAdjLocked(
@@ -12874,16 +12845,16 @@
                                     // about letting this process get into the LRU
                                     // list to be killed and restarted if needed for
                                     // memory.
-                                    if (app.hasShownUi && clientAdj > PERCEPTIBLE_APP_ADJ) {
+                                    if (app.hasShownUi && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                                         adjType = "bound-bg-ui-services";
                                     } else {
                                         if ((cr.flags&(Context.BIND_ABOVE_CLIENT
                                                 |Context.BIND_IMPORTANT)) != 0) {
                                             adj = clientAdj;
-                                        } else if (clientAdj >= VISIBLE_APP_ADJ) {
+                                        } else if (clientAdj >= ProcessList.VISIBLE_APP_ADJ) {
                                             adj = clientAdj;
                                         } else {
-                                            adj = VISIBLE_APP_ADJ;
+                                            adj = ProcessList.VISIBLE_APP_ADJ;
                                         }
                                         if (!client.hidden) {
                                             app.hidden = false;
@@ -12909,10 +12880,10 @@
                             }
                             if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
                                 ActivityRecord a = cr.activity;
-                                if (a != null && adj > FOREGROUND_APP_ADJ &&
+                                if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ &&
                                         (a.visible || a.state == ActivityState.RESUMED
                                          || a.state == ActivityState.PAUSING)) {
-                                    adj = FOREGROUND_APP_ADJ;
+                                    adj = ProcessList.FOREGROUND_APP_ADJ;
                                     if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
                                         schedGroup = Process.THREAD_GROUP_DEFAULT;
                                     }
@@ -12941,15 +12912,15 @@
             }
         }
 
-        if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ
+        if (app.pubProviders.size() != 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
             Iterator<ContentProviderRecord> jt = app.pubProviders.values().iterator();
-            while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ
+            while (jt.hasNext() && (adj > ProcessList.FOREGROUND_APP_ADJ
                     || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
                 ContentProviderRecord cpr = jt.next();
                 if (cpr.clients.size() != 0) {
                     Iterator<ProcessRecord> kt = cpr.clients.iterator();
-                    while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
+                    while (kt.hasNext() && adj > ProcessList.FOREGROUND_APP_ADJ) {
                         ProcessRecord client = kt.next();
                         if (client == app) {
                             // Being our own client is not interesting.
@@ -12957,20 +12928,20 @@
                         }
                         int myHiddenAdj = hiddenAdj;
                         if (myHiddenAdj > client.hiddenAdj) {
-                            if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
+                            if (client.hiddenAdj > ProcessList.FOREGROUND_APP_ADJ) {
                                 myHiddenAdj = client.hiddenAdj;
                             } else {
-                                myHiddenAdj = FOREGROUND_APP_ADJ;
+                                myHiddenAdj = ProcessList.FOREGROUND_APP_ADJ;
                             }
                         }
                         int clientAdj = computeOomAdjLocked(
                             client, myHiddenAdj, TOP_APP, true);
                         if (adj > clientAdj) {
-                            if (app.hasShownUi && clientAdj > PERCEPTIBLE_APP_ADJ) {
+                            if (app.hasShownUi && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                                 app.adjType = "bg-ui-provider";
                             } else {
-                                adj = clientAdj > FOREGROUND_APP_ADJ
-                                        ? clientAdj : FOREGROUND_APP_ADJ;
+                                adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
+                                        ? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
                                 app.adjType = "provider";
                             }
                             if (!client.hidden) {
@@ -12993,8 +12964,8 @@
                 // dependencies, ensure that its adjustment is at least
                 // FOREGROUND_APP_ADJ.
                 if (cpr.externals != 0) {
-                    if (adj > FOREGROUND_APP_ADJ) {
-                        adj = FOREGROUND_APP_ADJ;
+                    if (adj > ProcessList.FOREGROUND_APP_ADJ) {
+                        adj = ProcessList.FOREGROUND_APP_ADJ;
                         schedGroup = Process.THREAD_GROUP_DEFAULT;
                         app.hidden = false;
                         app.keeping = true;
@@ -13011,11 +12982,11 @@
         //      " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
         if (adj > app.maxAdj) {
             adj = app.maxAdj;
-            if (app.maxAdj <= PERCEPTIBLE_APP_ADJ) {
+            if (app.maxAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
                 schedGroup = Process.THREAD_GROUP_DEFAULT;
             }
         }
-        if (adj < HIDDEN_APP_MIN_ADJ) {
+        if (adj < ProcessList.HIDDEN_APP_MIN_ADJ) {
             app.keeping = true;
         }
 
@@ -13025,15 +12996,15 @@
             // in order to honor the request.  We want to drop it by one adjustment
             // level...  but there is special meaning applied to various levels so
             // we will skip some of them.
-            if (adj < FOREGROUND_APP_ADJ) {
+            if (adj < ProcessList.FOREGROUND_APP_ADJ) {
                 // System process will not get dropped, ever
-            } else if (adj < VISIBLE_APP_ADJ) {
-                adj = VISIBLE_APP_ADJ;
-            } else if (adj < PERCEPTIBLE_APP_ADJ) {
-                adj = PERCEPTIBLE_APP_ADJ;
-            } else if (adj < HIDDEN_APP_MIN_ADJ) {
-                adj = HIDDEN_APP_MIN_ADJ;
-            } else if (adj < EMPTY_APP_ADJ) {
+            } else if (adj < ProcessList.VISIBLE_APP_ADJ) {
+                adj = ProcessList.VISIBLE_APP_ADJ;
+            } else if (adj < ProcessList.PERCEPTIBLE_APP_ADJ) {
+                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+            } else if (adj < ProcessList.HIDDEN_APP_MIN_ADJ) {
+                adj = ProcessList.HIDDEN_APP_MIN_ADJ;
+            } else if (adj < ProcessList.EMPTY_APP_ADJ) {
                 adj++;
             }
         }
@@ -13090,7 +13061,7 @@
         if (canGcNowLocked()) {
             while (mProcessesToGc.size() > 0) {
                 ProcessRecord proc = mProcessesToGc.remove(0);
-                if (proc.curRawAdj > PERCEPTIBLE_APP_ADJ || proc.reportLowMemory) {
+                if (proc.curRawAdj > ProcessList.PERCEPTIBLE_APP_ADJ || proc.reportLowMemory) {
                     if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
                             <= SystemClock.uptimeMillis()) {
                         // To avoid spamming the system, we will GC processes one
@@ -13290,13 +13261,13 @@
         computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
 
         if (app.curRawAdj != app.setRawAdj) {
-            if (app.curRawAdj > FOREGROUND_APP_ADJ
-                    && app.setRawAdj <= FOREGROUND_APP_ADJ) {
+            if (app.curRawAdj > ProcessList.FOREGROUND_APP_ADJ
+                    && app.setRawAdj <= ProcessList.FOREGROUND_APP_ADJ) {
                 // If this app is transitioning from foreground to
                 // non-foreground, have it do a gc.
                 scheduleAppGcLocked(app);
-            } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
-                    && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
+            } else if (app.curRawAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
+                    && app.setRawAdj < ProcessList.HIDDEN_APP_MIN_ADJ) {
                 // Likewise do a gc when an app is moving in to the
                 // background (such as a service stopping).
                 scheduleAppGcLocked(app);
@@ -13376,14 +13347,14 @@
         final ActivityRecord TOP_ACT = resumedAppLocked();
         final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
         int curAdj = app.curAdj;
-        final boolean wasHidden = curAdj >= HIDDEN_APP_MIN_ADJ
-            && curAdj <= HIDDEN_APP_MAX_ADJ;
+        final boolean wasHidden = curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
+            && curAdj <= ProcessList.HIDDEN_APP_MAX_ADJ;
 
         mAdjSeq++;
 
         updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
-        final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
-            && app.curAdj <= HIDDEN_APP_MAX_ADJ;
+        final boolean nowHidden = app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
+            && app.curAdj <= ProcessList.HIDDEN_APP_MAX_ADJ;
         if (nowHidden != wasHidden) {
             // Changed to/from hidden state, so apps after it in the LRU
             // list may also be changed.
@@ -13407,7 +13378,7 @@
         // how many slots we have for background processes; we may want
         // to put multiple processes in a slot of there are enough of
         // them.
-        int numSlots = HIDDEN_APP_MAX_ADJ - HIDDEN_APP_MIN_ADJ + 1;
+        int numSlots = ProcessList.HIDDEN_APP_MAX_ADJ - ProcessList.HIDDEN_APP_MIN_ADJ + 1;
         int factor = (mLruProcesses.size()-4)/numSlots;
         if (factor < 1) factor = 1;
         int step = 0;
@@ -13416,14 +13387,14 @@
         // First update the OOM adjustment for each of the
         // application processes based on their current state.
         int i = mLruProcesses.size();
-        int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
+        int curHiddenAdj = ProcessList.HIDDEN_APP_MIN_ADJ;
         int numBg = 0;
         while (i > 0) {
             i--;
             ProcessRecord app = mLruProcesses.get(i);
             //Slog.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
             updateOomAdjLocked(app, curHiddenAdj, TOP_APP);
-            if (curHiddenAdj < EMPTY_APP_ADJ
+            if (curHiddenAdj < ProcessList.EMPTY_APP_ADJ
                 && app.curAdj == curHiddenAdj) {
                 step++;
                 if (step >= factor) {
@@ -13432,7 +13403,7 @@
                 }
             }
             if (!app.killedBackground) {
-                if (app.curAdj >= HIDDEN_APP_MIN_ADJ) {
+                if (app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
                     numHidden++;
                     if (numHidden > mProcessLimit) {
                         Slog.i(TAG, "No longer want " + app.processName
@@ -13444,7 +13415,7 @@
                     } else {
                         numBg++;
                     }
-                } else if (app.curAdj >= HOME_APP_ADJ) {
+                } else if (app.curAdj >= ProcessList.HOME_APP_ADJ) {
                     numBg++;
                 }
             }
@@ -13456,14 +13427,14 @@
         // are managing to keep around is less than half the maximum we desire;
         // if we are keeping a good number around, we'll let them use whatever
         // memory they want.
-        if (numHidden <= (MAX_HIDDEN_APPS/2)) {
+        if (numHidden <= (ProcessList.MAX_HIDDEN_APPS/2)) {
             final int N = mLruProcesses.size();
             factor = numBg/3;
             step = 0;
             int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
             for (i=0; i<N; i++) {
                 ProcessRecord app = mLruProcesses.get(i);
-                if (app.curAdj >= HIDDEN_APP_MIN_ADJ && !app.killedBackground) {
+                if (app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ && !app.killedBackground) {
                     if (app.trimMemoryLevel < curLevel && app.thread != null) {
                         try {
                             app.thread.scheduleTrimMemory(curLevel);
@@ -13487,7 +13458,7 @@
                                 break;
                         }
                     }
-                } else if (app.curAdj == HEAVY_WEIGHT_APP_ADJ) {
+                } else if (app.curAdj == ProcessList.HEAVY_WEIGHT_APP_ADJ) {
                     if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
                             && app.thread != null) {
                         try {
@@ -13497,7 +13468,7 @@
                         }
                     }
                     app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
-                } else if ((app.curAdj > VISIBLE_APP_ADJ || app.systemNoUi)
+                } else if ((app.curAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi)
                         && app.pendingUiClean) {
                     if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
                             && app.thread != null) {
@@ -13517,7 +13488,7 @@
             final int N = mLruProcesses.size();
             for (i=0; i<N; i++) {
                 ProcessRecord app = mLruProcesses.get(i);
-                if ((app.curAdj > VISIBLE_APP_ADJ || app.systemNoUi)
+                if ((app.curAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi)
                         && app.pendingUiClean) {
                     if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
                             && app.thread != null) {
diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java
new file mode 100644
index 0000000..dfcc0bf
--- /dev/null
+++ b/services/java/com/android/server/am/ProcessList.java
@@ -0,0 +1,221 @@
+/*
+ * 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.server.am;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import com.android.internal.util.MemInfoReader;
+import com.android.server.wm.WindowManagerService;
+
+import android.graphics.Point;
+import android.os.StrictMode;
+import android.util.Slog;
+
+/**
+ * Activity manager code dealing with processes.
+ */
+class ProcessList {
+    // The minimum time we allow between crashes, for us to consider this
+    // application to be bad and stop and its services and reject broadcasts.
+    static final int MIN_CRASH_INTERVAL = 60*1000;
+
+    // OOM adjustments for processes in various states:
+
+    // This is a process without anything currently running in it.  Definitely
+    // the first to go! Value set in system/rootdir/init.rc on startup.
+    // This value is initalized in the constructor, careful when refering to
+    // this static variable externally.
+    static final int EMPTY_APP_ADJ = 15;
+
+    // This is a process only hosting activities that are not visible,
+    // so it can be killed without any disruption. Value set in
+    // system/rootdir/init.rc on startup.
+    static final int HIDDEN_APP_MAX_ADJ = 15;
+    static int HIDDEN_APP_MIN_ADJ = 7;
+
+    // This is a process holding the home application -- we want to try
+    // avoiding killing it, even if it would normally be in the background,
+    // because the user interacts with it so much.
+    static final int HOME_APP_ADJ = 6;
+
+    // This is a process holding a secondary server -- killing it will not
+    // have much of an impact as far as the user is concerned. Value set in
+    // system/rootdir/init.rc on startup.
+    static final int SECONDARY_SERVER_ADJ = 5;
+
+    // This is a process currently hosting a backup operation.  Killing it
+    // is not entirely fatal but is generally a bad idea.
+    static final int BACKUP_APP_ADJ = 4;
+
+    // This is a process with a heavy-weight application.  It is in the
+    // background, but we want to try to avoid killing it.  Value set in
+    // system/rootdir/init.rc on startup.
+    static final int HEAVY_WEIGHT_APP_ADJ = 3;
+
+    // This is a process only hosting components that are perceptible to the
+    // user, and we really want to avoid killing them, but they are not
+    // immediately visible. An example is background music playback.  Value set in
+    // system/rootdir/init.rc on startup.
+    static final int PERCEPTIBLE_APP_ADJ = 2;
+
+    // This is a process only hosting activities that are visible to the
+    // user, so we'd prefer they don't disappear. Value set in
+    // system/rootdir/init.rc on startup.
+    static final int VISIBLE_APP_ADJ = 1;
+
+    // This is the process running the current foreground app.  We'd really
+    // rather not kill it! Value set in system/rootdir/init.rc on startup.
+    static final int FOREGROUND_APP_ADJ = 0;
+
+    // This is a process running a core server, such as telephony.  Definitely
+    // don't want to kill it, but doing so is not completely fatal.
+    static final int CORE_SERVER_ADJ = -12;
+
+    // The system process runs at the default adjustment.
+    static final int SYSTEM_ADJ = -16;
+
+    // Memory pages are 4K.
+    static final int PAGE_SIZE = 4*1024;
+
+    // The minimum number of hidden apps we want to be able to keep around,
+    // without empty apps being able to push them out of memory.
+    static final int MIN_HIDDEN_APPS = 2;
+
+    // The maximum number of hidden processes we will keep around before
+    // killing them; this is just a control to not let us go too crazy with
+    // keeping around processes on devices with large amounts of RAM.
+    static final int MAX_HIDDEN_APPS = 15;
+
+    // We put empty content processes after any hidden processes that have
+    // been idle for less than 15 seconds.
+    static final long CONTENT_APP_IDLE_OFFSET = 15*1000;
+
+    // We put empty content processes after any hidden processes that have
+    // been idle for less than 120 seconds.
+    static final long EMPTY_APP_IDLE_OFFSET = 120*1000;
+
+    // These are the various interesting memory levels that we will give to
+    // the OOM killer.  Note that the OOM killer only supports 6 slots, so we
+    // can't give it a different value for every possible kind of process.
+    private final int[] mOomAdj = new int[] {
+            FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,
+            BACKUP_APP_ADJ, HIDDEN_APP_MIN_ADJ, EMPTY_APP_ADJ
+    };
+    // These are the low-end OOM level limits.  This is appropriate for an
+    // HVGA or smaller phone with less than 512MB.  Values are in KB.
+    private final long[] mOomMinFreeLow = new long[] {
+            8192, 12288, 16384,
+            24576, 28672, 32768
+    };
+    // These are the high-end OOM level limits.  This is appropriate for a
+    // 1280x800 or larger screen with around 1GB RAM.  Values are in KB.
+    private final long[] mOomMinFreeHigh = new long[] {
+            32768, 40960, 49152,
+            57344, 65536, 81920
+    };
+    // The actual OOM killer memory levels we are using.
+    private final long[] mOomMinFree = new long[mOomAdj.length];
+
+    private final long mTotalMemMb;
+
+    private boolean mHaveDisplaySize;
+
+    ProcessList() {
+        MemInfoReader minfo = new MemInfoReader();
+        minfo.readMemInfo();
+        mTotalMemMb = minfo.getTotalSize()/(1024*1024);
+        updateOomLevels(0, 0, false);
+    }
+
+    void applyDisplaySize(WindowManagerService wm) {
+        if (!mHaveDisplaySize) {
+            Point p = new Point();
+            wm.getInitialDisplaySize(p);
+            if (p.x != 0 && p.y != 0) {
+                updateOomLevels(p.x, p.y, true);
+                mHaveDisplaySize = true;
+            }
+        }
+    }
+
+    private void updateOomLevels(int displayWidth, int displayHeight, boolean write) {
+        // Scale buckets from avail memory: at 300MB we use the lowest values to
+        // 700MB or more for the top values.
+        float scaleMem = ((float)(mTotalMemMb-300))/(700-300);
+
+        // Scale buckets from screen size.
+        int minSize = 320*480;  //  153600
+        int maxSize = 1280*800; // 1024000  230400 870400  .264
+        float scaleDisp = ((float)(displayWidth*displayHeight)-minSize)/(maxSize-minSize);
+        Slog.i("XXXXXX", "scaleDisp=" + scaleDisp + " dw=" + displayWidth + " dh=" + displayHeight);
+
+        StringBuilder adjString = new StringBuilder();
+        StringBuilder memString = new StringBuilder();
+
+        float scale = scaleMem > scaleDisp ? scaleMem : scaleDisp;
+        if (scale < 0) scale = 0;
+        else if (scale > 1) scale = 1;
+        for (int i=0; i<mOomAdj.length; i++) {
+            long low = mOomMinFreeLow[i];
+            long high = mOomMinFreeHigh[i];
+            mOomMinFree[i] = (long)(low + ((high-low)*scale));
+
+            if (i > 0) {
+                adjString.append(',');
+                memString.append(',');
+            }
+            adjString.append(mOomAdj[i]);
+            memString.append((mOomMinFree[i]*1024)/PAGE_SIZE);
+        }
+
+        //Slog.i("XXXXXXX", "******************************* MINFREE: " + memString);
+        if (write) {
+            writeFile("/sys/module/lowmemorykiller/parameters/adj", adjString.toString());
+            writeFile("/sys/module/lowmemorykiller/parameters/minfree", memString.toString());
+        }
+        // GB: 2048,3072,4096,6144,7168,8192
+        // HC: 8192,10240,12288,14336,16384,20480
+    }
+
+    long getMemLevel(int adjustment) {
+        for (int i=0; i<mOomAdj.length; i++) {
+            if (adjustment <= mOomAdj[i]) {
+                return mOomMinFree[i] * 1024;
+            }
+        }
+        return mOomMinFree[mOomAdj.length-1] * 1024;
+    }
+
+    private void writeFile(String path, String data) {
+        FileOutputStream fos = null;
+        try {
+            fos = new FileOutputStream(path);
+            fos.write(data.getBytes());
+        } catch (IOException e) {
+            Slog.w(ActivityManagerService.TAG, "Unable to write " + path);
+        } finally {
+            if (fos != null) {
+                try {
+                    fos.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index a896ce4..24d92cf 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -270,8 +270,8 @@
         processName = _processName;
         pkgList.add(_info.packageName);
         thread = _thread;
-        maxAdj = ActivityManagerService.EMPTY_APP_ADJ;
-        hiddenAdj = ActivityManagerService.HIDDEN_APP_MIN_ADJ;
+        maxAdj = ProcessList.EMPTY_APP_ADJ;
+        hiddenAdj = ProcessList.HIDDEN_APP_MIN_ADJ;
         curRawAdj = setRawAdj = -100;
         curAdj = setAdj = -100;
         persistent = false;
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index 9cb772e..b69cc31 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -54,7 +54,6 @@
 public class Vpn extends INetworkManagementEventObserver.Stub {
 
     private final static String TAG = "Vpn";
-    private final static String VPN = android.Manifest.permission.VPN;
 
     private final Context mContext;
     private final VpnCallback mCallback;
@@ -69,18 +68,6 @@
     }
 
     /**
-     * Protect a socket from routing changes by binding it to the given
-     * interface. The socket is NOT closed by this method.
-     *
-     * @param socket The socket to be bound.
-     * @param name The name of the interface.
-     */
-    public void protect(ParcelFileDescriptor socket, String interfaze) {
-        mContext.enforceCallingPermission(VPN, "protect");
-        jniProtect(socket.getFd(), interfaze);
-    }
-
-    /**
      * Prepare for a VPN application. This method is designed to solve
      * race conditions. It first compares the current prepared package
      * with {@code oldPackage}. If they are the same, the prepared
@@ -115,13 +102,6 @@
             throw new SecurityException("Unauthorized Caller");
         }
 
-        // Check the permission of the given package.
-        PackageManager pm = mContext.getPackageManager();
-        if (!newPackage.equals(VpnConfig.LEGACY_VPN) &&
-                pm.checkPermission(VPN, newPackage) != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException(newPackage + " does not have " + VPN);
-        }
-
         // Reset the interface and hide the notification.
         if (mInterface != null) {
             jniReset(mInterface);
@@ -130,12 +110,9 @@
             mInterface = null;
         }
 
-        // Send out the broadcast or stop LegacyVpnRunner.
+        // Revoke the connection or stop LegacyVpnRunner.
         if (!mPackage.equals(VpnConfig.LEGACY_VPN)) {
-            Intent intent = new Intent(VpnConfig.ACTION_VPN_REVOKED);
-            intent.setPackage(mPackage);
-            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-            mContext.sendBroadcast(intent);
+            // TODO
         } else if (mLegacyVpnRunner != null) {
             mLegacyVpnRunner.exit();
             mLegacyVpnRunner = null;
@@ -147,6 +124,22 @@
     }
 
     /**
+     * Protect a socket from routing changes by binding it to the given
+     * interface. The socket is NOT closed by this method.
+     *
+     * @param socket The socket to be bound.
+     * @param name The name of the interface.
+     */
+    public void protect(ParcelFileDescriptor socket, String interfaze) throws Exception {
+        PackageManager pm = mContext.getPackageManager();
+        ApplicationInfo app = pm.getApplicationInfo(mPackage, 0);
+        if (Binder.getCallingUid() != app.uid) {
+            throw new SecurityException("Unauthorized Caller");
+        }
+        jniProtect(socket.getFd(), interfaze);
+    }
+
+    /**
      * Establish a VPN network and return the file descriptor of the VPN
      * interface. This methods returns {@code null} if the application is
      * revoked or not prepared.
@@ -155,9 +148,6 @@
      * @return The file descriptor of the VPN interface.
      */
     public synchronized ParcelFileDescriptor establish(VpnConfig config) {
-        // Check the permission of the caller.
-        mContext.enforceCallingPermission(VPN, "establish");
-
         // Check if the caller is already prepared.
         PackageManager pm = mContext.getPackageManager();
         ApplicationInfo app = null;
@@ -170,6 +160,9 @@
             return null;
         }
 
+        // Check if the service is properly declared.
+        // TODO
+
         // Load the label.
         String label = app.loadLabel(pm).toString();
 
@@ -183,7 +176,9 @@
                     android.R.dimen.notification_large_icon_height);
             icon.setBounds(0, 0, width, height);
             bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-            icon.draw(new Canvas(bitmap));
+            Canvas c = new Canvas(bitmap);
+            icon.draw(c);
+            c.setBitmap(null);
         }
 
         // Configure the interface. Abort if any of these steps fails.
@@ -196,6 +191,7 @@
             if (config.routes != null) {
                 jniSetRoutes(interfaze, config.routes);
             }
+            // TODO: bind the service
             if (mInterface != null && !mInterface.equals(interfaze)) {
                 jniReset(mInterface);
             }
@@ -209,23 +205,25 @@
             throw e;
         }
 
-        // Override DNS servers and search domains.
-        mCallback.override(config.dnsServers, config.searchDomains);
-
         // Fill more values.
-        config.packagz = mPackage;
+        config.user = mPackage;
         config.interfaze = mInterface;
 
-        // Show the notification!
+        // Override DNS servers and show the notification.
+        long identity = Binder.clearCallingIdentity();
+        mCallback.override(config.dnsServers, config.searchDomains);
         showNotification(config, label, bitmap);
+        Binder.restoreCallingIdentity(identity);
         return tun;
     }
 
     // INetworkManagementEventObserver.Stub
+    @Override
     public void interfaceAdded(String interfaze) {
     }
 
     // INetworkManagementEventObserver.Stub
+    @Override
     public synchronized void interfaceStatusChanged(String interfaze, boolean up) {
         if (!up && mLegacyVpnRunner != null) {
             mLegacyVpnRunner.check(interfaze);
@@ -233,23 +231,29 @@
     }
 
     // INetworkManagementEventObserver.Stub
-    public synchronized void interfaceLinkStateChanged(String interfaze, boolean up) {
-        if (!up && mLegacyVpnRunner != null) {
-            mLegacyVpnRunner.check(interfaze);
+    @Override
+    public void interfaceLinkStateChanged(String interfaze, boolean up) {
+        interfaceStatusChanged(interfaze, up);
+    }
+
+    // INetworkManagementEventObserver.Stub
+    @Override
+    public synchronized void interfaceRemoved(String interfaze) {
+        if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
+            long identity = Binder.clearCallingIdentity();
+            mCallback.restore();
+            hideNotification();
+            Binder.restoreCallingIdentity(identity);
+            mInterface = null;
+            // TODO: unbind the service
         }
     }
 
     // INetworkManagementEventObserver.Stub
-    public synchronized void interfaceRemoved(String interfaze) {
-        if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
-            mCallback.restore();
-            hideNotification();
-            mInterface = null;
-        }
+    @Override
+    public void limitReached(String limit, String interfaze) {
     }
 
-    public void limitReached(String limitName, String iface) {}
-
     private void showNotification(VpnConfig config, String label, Bitmap icon) {
         NotificationManager nm = (NotificationManager)
                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -261,7 +265,6 @@
                     mContext.getString(R.string.vpn_text_long, config.session);
             config.startTime = SystemClock.elapsedRealtime();
 
-            long identity = Binder.clearCallingIdentity();
             Notification notification = new Notification.Builder(mContext)
                     .setSmallIcon(R.drawable.vpn_connected)
                     .setLargeIcon(icon)
@@ -272,7 +275,6 @@
                     .setOngoing(true)
                     .getNotification();
             nm.notify(R.drawable.vpn_connected, notification);
-            Binder.restoreCallingIdentity(identity);
         }
     }
 
@@ -281,9 +283,7 @@
                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
 
         if (nm != null) {
-            long identity = Binder.clearCallingIdentity();
             nm.cancel(R.drawable.vpn_connected);
-            Binder.restoreCallingIdentity(identity);
         }
     }
 
@@ -353,8 +353,8 @@
             mOuterInterface = mConfig.interfaze;
 
             // Legacy VPN is not a real package, so we use it to carry the key.
-            mInfo.key = mConfig.packagz;
-            mConfig.packagz = VpnConfig.LEGACY_VPN;
+            mInfo.key = mConfig.user;
+            mConfig.user = VpnConfig.LEGACY_VPN;
         }
 
         public void check(String interfaze) {
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index b79e31f..0ce5499 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.database.Cursor;
 import android.location.Criteria;
 import android.location.IGpsStatusListener;
 import android.location.IGpsStatusProvider;
@@ -32,6 +33,7 @@
 import android.location.LocationProvider;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -45,6 +47,7 @@
 import android.os.SystemClock;
 import android.os.WorkSource;
 import android.provider.Settings;
+import android.provider.Telephony.Carriers;
 import android.provider.Telephony.Sms.Intents;
 import android.telephony.SmsMessage;
 import android.telephony.TelephonyManager;
@@ -489,8 +492,17 @@
         }
 
         if (info != null) {
+            boolean dataEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
+                                                         Settings.Secure.MOBILE_DATA, 1) == 1;
+            boolean networkAvailable = info.isAvailable() && dataEnabled;
+            String defaultApn = getSelectedApn();
+            if (defaultApn == null) {
+                defaultApn = "dummy-apn";
+            }
+
             native_update_network_state(info.isConnected(), info.getType(),
-                    info.isRoaming(), info.getExtraInfo());
+                                        info.isRoaming(), networkAvailable,
+                                        info.getExtraInfo(), defaultApn);
         }
 
         if (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE_SUPL
@@ -1597,6 +1609,25 @@
         }
     }
 
+    private String getSelectedApn() {
+        Uri uri = Uri.parse("content://telephony/carriers/preferapn");
+        String apn = null;
+
+        Cursor cursor = mContext.getContentResolver().query(uri, new String[] {"apn"},
+                null, null, Carriers.DEFAULT_SORT_ORDER);
+
+        if (null != cursor) {
+            try {
+                if (cursor.moveToFirst()) {
+                    apn = cursor.getString(0);
+                }
+            } finally {
+                cursor.close();
+            }
+        }
+        return apn;
+    }
+
     // for GPS SV statistics
     private static final int MAX_SVS = 32;
     private static final int EPHEMERIS_MASK = 0;
@@ -1655,5 +1686,5 @@
     private native void native_agps_set_id(int type, String setid);
 
     private native void native_update_network_state(boolean connected, int type,
-            boolean roaming, String extraInfo);
+            boolean roaming, boolean available, String extraInfo, String defaultAPN);
 }
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 756cd00..a075255 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.net;
 
+import static android.Manifest.permission.ACCESS_NETWORK_STATE;
 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
 import static android.Manifest.permission.DUMP;
 import static android.Manifest.permission.MANAGE_APP_TOKENS;
@@ -75,9 +76,11 @@
 import android.net.INetworkStatsService;
 import android.net.NetworkIdentity;
 import android.net.NetworkPolicy;
+import android.net.NetworkQuotaInfo;
 import android.net.NetworkState;
 import android.net.NetworkStats;
 import android.net.NetworkTemplate;
+import android.os.Binder;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -1054,6 +1057,7 @@
         synchronized (mRulesLock) {
             mRestrictBackground = restrictBackground;
             updateRulesForRestrictBackgroundLocked();
+            writePolicyLocked();
         }
     }
 
@@ -1066,6 +1070,68 @@
         }
     }
 
+    private NetworkPolicy findPolicyForNetworkLocked(NetworkIdentity ident) {
+        for (NetworkPolicy policy : mNetworkPolicy.values()) {
+            if (policy.template.matches(ident)) {
+                return policy;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public NetworkQuotaInfo getNetworkQuotaInfo(NetworkState state) {
+        mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
+
+        // only returns usage summary, so we don't require caller to have
+        // READ_NETWORK_USAGE_HISTORY.
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return getNetworkQuotaInfoUnchecked(state);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    private NetworkQuotaInfo getNetworkQuotaInfoUnchecked(NetworkState state) {
+        final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
+
+        final NetworkPolicy policy;
+        synchronized (mRulesLock) {
+            policy = findPolicyForNetworkLocked(ident);
+        }
+
+        if (policy == null) {
+            // missing policy means we can't derive useful quota info
+            return null;
+        }
+
+        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
+                : System.currentTimeMillis();
+
+        final long start = computeLastCycleBoundary(currentTime, policy);
+        final long end = currentTime;
+
+        // find total bytes used under policy
+        long totalBytes = 0;
+        try {
+            final NetworkStats stats = mNetworkStats.getSummaryForNetwork(
+                    policy.template, start, end);
+            final NetworkStats.Entry entry = stats.getValues(0, null);
+            totalBytes = entry.rxBytes + entry.txBytes;
+        } catch (RemoteException e) {
+            Slog.w(TAG, "problem reading summary for template " + policy.template);
+        }
+
+        // report soft and hard limits under policy
+        final long softLimitBytes = policy.warningBytes != WARNING_DISABLED ? policy.warningBytes
+                : NetworkQuotaInfo.NO_LIMIT;
+        final long hardLimitBytes = policy.limitBytes != LIMIT_DISABLED ? policy.limitBytes
+                : NetworkQuotaInfo.NO_LIMIT;
+
+        return new NetworkQuotaInfo(totalBytes, softLimitBytes, hardLimitBytes);
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
         mContext.enforceCallingOrSelfPermission(DUMP, TAG);
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 24188ca..deca7a9 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -16,10 +16,10 @@
 
 package com.android.server.net;
 
-import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
 import static android.Manifest.permission.ACCESS_NETWORK_STATE;
-import static android.Manifest.permission.MODIFY_NETWORK_ACCOUNTING;
+import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
 import static android.Manifest.permission.DUMP;
+import static android.Manifest.permission.MODIFY_NETWORK_ACCOUNTING;
 import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
 import static android.content.Intent.ACTION_SHUTDOWN;
 import static android.content.Intent.ACTION_UID_REMOVED;
@@ -68,7 +68,6 @@
 import android.os.SystemClock;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
-import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.NtpTrustedTime;
 import android.util.Slog;
@@ -282,13 +281,13 @@
     }
 
     @Override
-    public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template) {
+    public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
         mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
 
         synchronized (mStatsLock) {
             // combine all interfaces that match template
             final NetworkStatsHistory combined = new NetworkStatsHistory(
-                    mSettings.getNetworkBucketDuration(), estimateNetworkBuckets());
+                    mSettings.getNetworkBucketDuration(), estimateNetworkBuckets(), fields);
             for (NetworkIdentitySet ident : mNetworkStats.keySet()) {
                 if (templateMatches(template, ident)) {
                     final NetworkStatsHistory history = mNetworkStats.get(ident);
@@ -302,7 +301,8 @@
     }
 
     @Override
-    public NetworkStatsHistory getHistoryForUid(NetworkTemplate template, int uid, int tag) {
+    public NetworkStatsHistory getHistoryForUid(
+            NetworkTemplate template, int uid, int tag, int fields) {
         mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
 
         synchronized (mStatsLock) {
@@ -311,7 +311,7 @@
 
             // combine all interfaces that match template
             final NetworkStatsHistory combined = new NetworkStatsHistory(
-                    mSettings.getUidBucketDuration(), estimateUidBuckets());
+                    mSettings.getUidBucketDuration(), estimateUidBuckets(), fields);
             for (NetworkIdentitySet ident : mUidStats.keySet()) {
                 if (templateMatches(template, ident)) {
                     final NetworkStatsHistory history = mUidStats.get(ident).get(packed);
@@ -596,7 +596,7 @@
 
         // decide if enough has changed to trigger persist
         final NetworkStats persistDelta = computeStatsDelta(
-                mLastPersistNetworkSnapshot, networkSnapshot);
+                mLastPersistNetworkSnapshot, networkSnapshot, true);
         final long persistThreshold = mSettings.getPersistThreshold();
 
         NetworkStats.Entry entry = null;
@@ -626,7 +626,7 @@
     private void performNetworkPollLocked(NetworkStats networkSnapshot, long currentTime) {
         final HashSet<String> unknownIface = Sets.newHashSet();
 
-        final NetworkStats delta = computeStatsDelta(mLastNetworkSnapshot, networkSnapshot);
+        final NetworkStats delta = computeStatsDelta(mLastNetworkSnapshot, networkSnapshot, false);
         final long timeStart = currentTime - delta.getElapsedRealtime();
 
         NetworkStats.Entry entry = null;
@@ -661,9 +661,9 @@
     private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) {
         ensureUidStatsLoadedLocked();
 
-        final NetworkStats delta = computeStatsDelta(mLastUidSnapshot, uidSnapshot);
+        final NetworkStats delta = computeStatsDelta(mLastUidSnapshot, uidSnapshot, false);
         final NetworkStats operationsDelta = computeStatsDelta(
-                mLastOperationsSnapshot, mOperations);
+                mLastOperationsSnapshot, mOperations, false);
         final long timeStart = currentTime - delta.getElapsedRealtime();
 
         NetworkStats.Entry entry = null;
@@ -932,6 +932,7 @@
             out.flush();
             mNetworkFile.finishWrite(fos);
         } catch (IOException e) {
+            Slog.w(TAG, "problem writing stats: ", e);
             if (fos != null) {
                 mNetworkFile.failWrite(fos);
             }
@@ -978,6 +979,7 @@
             out.flush();
             mUidFile.finishWrite(fos);
         } catch (IOException e) {
+            Slog.w(TAG, "problem writing stats: ", e);
             if (fos != null) {
                 mUidFile.failWrite(fos);
             }
@@ -1052,15 +1054,20 @@
      */
     @Deprecated
     private void generateRandomLocked() {
-        long networkEnd = System.currentTimeMillis();
-        long networkStart = networkEnd - mSettings.getNetworkMaxHistory();
-        long networkRx = 3 * GB_IN_BYTES;
-        long networkTx = 2 * GB_IN_BYTES;
+        final long NET_END = System.currentTimeMillis();
+        final long NET_START = NET_END - mSettings.getNetworkMaxHistory();
+        final long NET_RX_BYTES = 3 * GB_IN_BYTES;
+        final long NET_RX_PACKETS = NET_RX_BYTES / 1024;
+        final long NET_TX_BYTES = 2 * GB_IN_BYTES;
+        final long NET_TX_PACKETS = NET_TX_BYTES / 1024;
 
-        long uidEnd = System.currentTimeMillis();
-        long uidStart = uidEnd - mSettings.getUidMaxHistory();
-        long uidRx = 500 * MB_IN_BYTES;
-        long uidTx = 100 * MB_IN_BYTES;
+        final long UID_END = System.currentTimeMillis();
+        final long UID_START = UID_END - mSettings.getUidMaxHistory();
+        final long UID_RX_BYTES = 500 * MB_IN_BYTES;
+        final long UID_RX_PACKETS = UID_RX_BYTES / 1024;
+        final long UID_TX_BYTES = 100 * MB_IN_BYTES;
+        final long UID_TX_PACKETS = UID_TX_BYTES / 1024;
+        final long UID_OPERATIONS = UID_RX_BYTES / 2048;
 
         final List<ApplicationInfo> installedApps = mContext
                 .getPackageManager().getInstalledApplications(0);
@@ -1068,13 +1075,13 @@
         mNetworkStats.clear();
         mUidStats.clear();
         for (NetworkIdentitySet ident : mActiveIfaces.values()) {
-            findOrCreateNetworkStatsLocked(ident).generateRandom(
-                    networkStart, networkEnd, networkRx, networkTx);
+            findOrCreateNetworkStatsLocked(ident).generateRandom(NET_START, NET_END, NET_RX_BYTES,
+                    NET_RX_PACKETS, NET_TX_BYTES, NET_TX_PACKETS, 0L);
 
             for (ApplicationInfo info : installedApps) {
                 final int uid = info.uid;
-                findOrCreateUidStatsLocked(ident, uid, TAG_NONE).generateRandom(
-                        uidStart, uidEnd, uidRx, uidTx);
+                findOrCreateUidStatsLocked(ident, uid, TAG_NONE).generateRandom(UID_START, UID_END,
+                        UID_RX_BYTES, UID_RX_PACKETS, UID_TX_BYTES, UID_TX_PACKETS, UID_OPERATIONS);
             }
         }
     }
@@ -1083,9 +1090,13 @@
      * Return the delta between two {@link NetworkStats} snapshots, where {@code
      * before} can be {@code null}.
      */
-    private static NetworkStats computeStatsDelta(NetworkStats before, NetworkStats current) {
+    private static NetworkStats computeStatsDelta(
+            NetworkStats before, NetworkStats current, boolean collectStale) {
         if (before != null) {
             return current.subtractClamped(before);
+        } else if (collectStale) {
+            // caller is okay collecting stale stats for first call.
+            return current;
         } else {
             // this is first snapshot; to prevent from double-counting we only
             // observe traffic occuring between known snapshots.
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 88e0fa8..463f801 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -432,7 +432,7 @@
         PackageHandler(Looper looper) {
             super(looper);
         }
-        
+
         public void handleMessage(Message msg) {
             try {
                 doHandleMessage(msg);
@@ -490,7 +490,34 @@
                     } else if (mPendingInstalls.size() > 0) {
                         HandlerParams params = mPendingInstalls.get(0);
                         if (params != null) {
-                            params.startCopy();
+                            if (params.startCopy()) {
+                                // We are done...  look for more work or to
+                                // go idle.
+                                if (DEBUG_SD_INSTALL) Log.i(TAG,
+                                        "Checking for more work or unbind...");
+                                // Delete pending install
+                                if (mPendingInstalls.size() > 0) {
+                                    mPendingInstalls.remove(0);
+                                }
+                                if (mPendingInstalls.size() == 0) {
+                                    if (mBound) {
+                                        if (DEBUG_SD_INSTALL) Log.i(TAG,
+                                                "Posting delayed MCS_UNBIND");
+                                        removeMessages(MCS_UNBIND);
+                                        Message ubmsg = obtainMessage(MCS_UNBIND);
+                                        // Unbind after a little delay, to avoid
+                                        // continual thrashing.
+                                        sendMessageDelayed(ubmsg, 10000);
+                                    }
+                                } else {
+                                    // There are more pending requests in queue.
+                                    // 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");
+                                    mHandler.sendEmptyMessage(MCS_BOUND);
+                                }
+                            }
                         }
                     } else {
                         // Should never happen ideally.
@@ -517,11 +544,8 @@
                     break;
                 }
                 case MCS_UNBIND : {
+                    // If there is no actual work left, then time to unbind.
                     if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_unbind");
-                    // Delete pending install
-                    if (mPendingInstalls.size() > 0) {
-                        mPendingInstalls.remove(0);
-                    }
                     if (mPendingInstalls.size() == 0) {
                         if (mBound) {
                             disconnectService();
@@ -3326,7 +3350,7 @@
         if (pkg.applicationInfo.nativeLibraryDir != null) {
             try {
                 final File nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
-                final String dataPathString = dataPath.getCanonicalFile().getPath();
+                final String dataPathString = dataPath.getCanonicalPath();
 
                 if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) {
                     /*
@@ -3340,7 +3364,7 @@
                         Log.i(TAG, "removed obsolete native libraries for system package "
                                 + path);
                     }
-                } else if (nativeLibraryDir.getCanonicalFile().getParent()
+                } else if (nativeLibraryDir.getParentFile().getCanonicalPath()
                         .equals(dataPathString)) {
                     /*
                      * Make sure the native library dir isn't a symlink to
@@ -4814,7 +4838,8 @@
     abstract class HandlerParams {
         final static int MAX_RETRIES = 4;
         int retry = 0;
-        final void startCopy() {
+        final boolean startCopy() {
+            boolean res;
             try {
                 if (DEBUG_SD_INSTALL) Log.i(TAG, "startCopy");
                 retry++;
@@ -4822,17 +4847,18 @@
                     Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
                     mHandler.sendEmptyMessage(MCS_GIVE_UP);
                     handleServiceError();
-                    return;
+                    return false;
                 } else {
                     handleStartCopy();
-                    if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_UNBIND");
-                    mHandler.sendEmptyMessage(MCS_UNBIND);
+                    res = true;
                 }
             } catch (RemoteException e) {
                 if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_RECONNECT");
                 mHandler.sendEmptyMessage(MCS_RECONNECT);
+                res = false;
             }
             handleReturnCode();
+            return res;
         }
 
         final void serviceError() {
@@ -5025,16 +5051,18 @@
                 }
 
                 int loc = pkgLite.recommendedInstallLocation;
-                if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION){
+                if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
                     ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
-                } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS){
+                } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
                     ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
-                } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE){
+                } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
                     ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                 } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
                     ret = PackageManager.INSTALL_FAILED_INVALID_APK;
+                } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
+                    ret = PackageManager.INSTALL_FAILED_INVALID_URI;
                 } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
-                  ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
+                    ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
                 } else {
                     // Override with defaults if needed.
                     loc = installLocationPolicy(pkgLite, flags);
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 86de880..91c5e33 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -382,7 +382,7 @@
                 mAdbEnabled = enable;
                 // Due to the persist.sys.usb.config property trigger, changing adb state requires
                 // switching to default function
-                setEnabledFunctions(mDefaultFunctions, false);
+                setEnabledFunctions(mDefaultFunctions, true);
                 updateAdbNotification();
             }
         }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index f8059f5..f80be1b 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -95,6 +95,7 @@
 import android.util.SparseIntArray;
 import android.util.TypedValue;
 import android.view.Display;
+import android.view.Gravity;
 import android.view.IApplicationToken;
 import android.view.IOnKeyguardExitResult;
 import android.view.IRotationWatcher;
@@ -4919,6 +4920,7 @@
         matrix.postTranslate(-(int)(frame.left*scale), -(int)(frame.top*scale));
         Canvas canvas = new Canvas(bm);
         canvas.drawBitmap(rawss, matrix, null);
+        canvas.setBitmap(null);
 
         rawss.recycle();
         return bm;
@@ -5162,6 +5164,57 @@
     }
 
     /**
+     * Apps that use the compact menu panel (as controlled by the panelMenuIsCompact
+     * theme attribute) on devices that feature a physical options menu key attempt to position
+     * their menu panel window along the edge of the screen nearest the physical menu key.
+     * This lowers the travel distance between invoking the menu panel and selecting
+     * a menu option.
+     *
+     * This method helps control where that menu is placed. Its current implementation makes
+     * assumptions about the menu key and its relationship to the screen based on whether
+     * the device's natural orientation is portrait (width < height) or landscape.
+     *
+     * The menu key is assumed to be located along the bottom edge of natural-portrait
+     * devices and along the right edge of natural-landscape devices. If these assumptions
+     * do not hold for the target device, this method should be changed to reflect that.
+     *
+     * @return A {@link Gravity} value for placing the options menu window
+     */
+    public int getPreferredOptionsPanelGravity() {
+        synchronized (mWindowMap) {
+            final int rotation = getRotation();
+
+            if (mInitialDisplayWidth < mInitialDisplayHeight) {
+                // On devices with a natural orientation of portrait
+                switch (rotation) {
+                    default:
+                    case Surface.ROTATION_0:
+                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+                    case Surface.ROTATION_90:
+                        return Gravity.RIGHT | Gravity.CENTER_VERTICAL;
+                    case Surface.ROTATION_180:
+                        return Gravity.CENTER_HORIZONTAL | Gravity.TOP;
+                    case Surface.ROTATION_270:
+                        return Gravity.LEFT | Gravity.CENTER_VERTICAL;
+                }
+            } else {
+                // On devices with a natural orientation of landscape
+                switch (rotation) {
+                    default:
+                    case Surface.ROTATION_0:
+                        return Gravity.RIGHT | Gravity.CENTER_VERTICAL;
+                    case Surface.ROTATION_90:
+                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+                    case Surface.ROTATION_180:
+                        return Gravity.LEFT | Gravity.CENTER_VERTICAL;
+                    case Surface.ROTATION_270:
+                        return Gravity.CENTER_HORIZONTAL | Gravity.TOP;
+                }
+            }
+        }
+    }
+
+    /**
      * Starts the view server on the specified port.
      *
      * @param port The port to listener to.
@@ -6611,6 +6664,13 @@
         }
     }
 
+    public void getInitialDisplaySize(Point size) {
+        synchronized(mWindowMap) {
+            size.x = mInitialDisplayWidth;
+            size.y = mInitialDisplayHeight;
+        }
+    }
+
     public int getMaximumSizeDimension() {
         synchronized(mWindowMap) {
             // Do this based on the raw screen size, until we are smarter.
diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp
index c29be3a..c823da5 100755
--- a/services/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -543,7 +543,7 @@
 }
 
 static void android_location_GpsLocationProvider_update_network_state(JNIEnv* env, jobject obj,
-        jboolean connected, int type, jboolean roaming, jstring extraInfo)
+        jboolean connected, int type, jboolean roaming, jboolean available, jstring extraInfo, jstring apn)
 {
 
     if (sAGpsRilInterface && sAGpsRilInterface->update_network_state) {
@@ -554,6 +554,14 @@
         } else {
             sAGpsRilInterface->update_network_state(connected, type, roaming, NULL);
         }
+
+        // update_network_availability callback was not included in original AGpsRilInterface
+        if (sAGpsRilInterface->size >= sizeof(AGpsRilInterface)
+                && sAGpsRilInterface->update_network_availability) {
+            const char *c_apn = env->GetStringUTFChars(apn, NULL);
+            sAGpsRilInterface->update_network_availability(available, c_apn);
+            env->ReleaseStringUTFChars(apn, c_apn);
+        }
     }
 }
 
@@ -582,7 +590,7 @@
     {"native_send_ni_response", "(II)V", (void*)android_location_GpsLocationProvider_send_ni_response},
     {"native_agps_ni_message", "([BI)V", (void *)android_location_GpsLocationProvider_agps_send_ni_message},
     {"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state},
-    {"native_update_network_state", "(ZIZLjava/lang/String;)V", (void*)android_location_GpsLocationProvider_update_network_state },
+    {"native_update_network_state", "(ZIZZLjava/lang/String;Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_update_network_state },
 };
 
 int register_android_server_location_GpsLocationProvider(JNIEnv* env)
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 7bf3e0a..f4be168 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -40,6 +40,7 @@
 
 #include "GLExtensions.h"
 #include "HWComposer.h"
+#include "SurfaceFlinger.h"
 
 using namespace android;
 
@@ -75,7 +76,7 @@
         const sp<SurfaceFlinger>& flinger,
         uint32_t dpy)
     : DisplayHardwareBase(flinger, dpy),
-      mFlags(0), mHwc(0)
+      mFlinger(flinger), mFlags(0), mHwc(0)
 {
     init(dpy);
 }
@@ -310,7 +311,7 @@
 
 
     // initialize the H/W composer
-    mHwc = new HWComposer();
+    mHwc = new HWComposer(mFlinger);
     if (mHwc->initCheck() == NO_ERROR) {
         mHwc->setFrameBuffer(mDisplay, mSurface);
     }
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index cdf89fd..40a6f1e 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -95,6 +95,7 @@
     void init(uint32_t displayIndex) __attribute__((noinline));
     void fini() __attribute__((noinline));
 
+    sp<SurfaceFlinger> mFlinger;
     EGLDisplay      mDisplay;
     EGLSurface      mSurface;
     EGLContext      mContext;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
index 30eb258..3ebc7b6 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
@@ -37,7 +37,7 @@
 
                 ~DisplayHardwareBase();
 
-    // console managment
+    // console management
     void releaseScreen() const;
     void acquireScreen() const;
     bool isScreenAcquired() const;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 4a3b20d..7d1bdf0 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -30,12 +30,14 @@
 #include <EGL/egl.h>
 
 #include "HWComposer.h"
+#include "SurfaceFlinger.h"
 
 namespace android {
 // ---------------------------------------------------------------------------
 
-HWComposer::HWComposer()
-    : mModule(0), mHwc(0), mList(0), mCapacity(0),
+HWComposer::HWComposer(const sp<SurfaceFlinger>& flinger)
+    : mFlinger(flinger),
+      mModule(0), mHwc(0), mList(0), mCapacity(0),
       mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE)
 {
     int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
@@ -44,6 +46,13 @@
         err = hwc_open(mModule, &mHwc);
         LOGE_IF(err, "%s device failed to initialize (%s)",
                 HWC_HARDWARE_COMPOSER, strerror(-err));
+        if (err == 0) {
+            if (mHwc->registerProcs) {
+                mCBContext.hwc = this;
+                mCBContext.procs.invalidate = &hook_invalidate;
+                mHwc->registerProcs(mHwc, &mCBContext.procs);
+            }
+        }
     }
 }
 
@@ -58,6 +67,14 @@
     return mHwc ? NO_ERROR : NO_INIT;
 }
 
+void HWComposer::hook_invalidate(struct hwc_procs* procs) {
+    reinterpret_cast<cb_context *>(procs)->hwc->invalidate();
+}
+
+void HWComposer::invalidate() {
+    mFlinger->signalEvent();
+}
+
 void HWComposer::setFrameBuffer(EGLDisplay dpy, EGLSurface sur) {
     mDpy = (hwc_display_t)dpy;
     mSur = (hwc_surface_t)sur;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 5a9e9eb..983898a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -24,16 +24,19 @@
 
 #include <hardware/hwcomposer.h>
 
+#include <utils/StrongPointer.h>
+
 namespace android {
 // ---------------------------------------------------------------------------
 
 class String8;
+class SurfaceFlinger;
 
 class HWComposer
 {
 public:
 
-    HWComposer();
+    HWComposer(const sp<SurfaceFlinger>& flinger);
     ~HWComposer();
 
     status_t initCheck() const;
@@ -60,12 +63,21 @@
     void dump(String8& out, char* scratch, size_t SIZE) const;
 
 private:
+    struct cb_context {
+        hwc_procs_t procs;
+        HWComposer* hwc;
+    };
+    static void hook_invalidate(struct hwc_procs* procs);
+    void invalidate();
+
+    sp<SurfaceFlinger>      mFlinger;
     hw_module_t const*      mModule;
     hwc_composer_device_t*  mHwc;
     hwc_layer_list_t*       mList;
     size_t                  mCapacity;
     hwc_display_t           mDpy;
     hwc_surface_t           mSur;
+    cb_context              mCBContext;
 };
 
 
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 886bb2a..383c045 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -172,17 +172,14 @@
 
 void Layer::setGeometry(hwc_layer_t* hwcl)
 {
-    hwcl->compositionType = HWC_FRAMEBUFFER;
-    hwcl->hints = 0;
-    hwcl->flags = 0;
-    hwcl->transform = 0;
-    hwcl->blending = HWC_BLENDING_NONE;
+    LayerBaseClient::setGeometry(hwcl);
+
+    hwcl->flags &= ~HWC_SKIP_LAYER;
 
     // we can't do alpha-fade with the hwc HAL
     const State& s(drawingState());
     if (s.alpha < 0xFF) {
         hwcl->flags = HWC_SKIP_LAYER;
-        return;
     }
 
     /*
@@ -205,26 +202,9 @@
     // we can only handle simple transformation
     if (finalTransform & Transform::ROT_INVALID) {
         hwcl->flags = HWC_SKIP_LAYER;
-        return;
+    } else {
+        hwcl->transform = finalTransform;
     }
-
-    hwcl->transform = finalTransform;
-
-    if (!isOpaque()) {
-        hwcl->blending = mPremultipliedAlpha ?
-                HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
-    }
-
-    // scaling is already applied in mTransformedBounds
-    hwcl->displayFrame.left   = mTransformedBounds.left;
-    hwcl->displayFrame.top    = mTransformedBounds.top;
-    hwcl->displayFrame.right  = mTransformedBounds.right;
-    hwcl->displayFrame.bottom = mTransformedBounds.bottom;
-
-    hwcl->visibleRegionScreen.rects =
-            reinterpret_cast<hwc_rect_t const *>(
-                    visibleRegionScreen.getArray(
-                            &hwcl->visibleRegionScreen.numRects));
 }
 
 void Layer::setPerFrameData(hwc_layer_t* hwcl) {
@@ -235,9 +215,9 @@
         // HWC handle it.
         hwcl->flags |= HWC_SKIP_LAYER;
         hwcl->handle = NULL;
-        return;
+    } else {
+        hwcl->handle = buffer->handle;
     }
-    hwcl->handle = buffer->handle;
 
     if (isCropped()) {
         hwcl->sourceCrop.left   = mCurrentCrop.left;
@@ -247,8 +227,13 @@
     } else {
         hwcl->sourceCrop.left   = 0;
         hwcl->sourceCrop.top    = 0;
-        hwcl->sourceCrop.right  = buffer->width;
-        hwcl->sourceCrop.bottom = buffer->height;
+        if (buffer != NULL) {
+            hwcl->sourceCrop.right  = buffer->width;
+            hwcl->sourceCrop.bottom = buffer->height;
+        } else {
+            hwcl->sourceCrop.right  = mTransformedBounds.width();
+            hwcl->sourceCrop.bottom = mTransformedBounds.height();
+        }
     }
 }
 
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index c86c659..e04c533 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -302,13 +302,47 @@
     }
 }
 
-void LayerBase::setGeometry(hwc_layer_t* hwcl) {
-    hwcl->flags |= HWC_SKIP_LAYER;
+void LayerBase::setGeometry(hwc_layer_t* hwcl)
+{
+    hwcl->compositionType = HWC_FRAMEBUFFER;
+    hwcl->hints = 0;
+    hwcl->flags = HWC_SKIP_LAYER;
+    hwcl->transform = 0;
+    hwcl->blending = HWC_BLENDING_NONE;
+
+    // this gives us only the "orientation" component of the transform
+    const State& s(drawingState());
+    const uint32_t finalTransform = s.transform.getOrientation();
+    // we can only handle simple transformation
+    if (finalTransform & Transform::ROT_INVALID) {
+        hwcl->flags = HWC_SKIP_LAYER;
+    } else {
+        hwcl->transform = finalTransform;
+    }
+
+    if (!isOpaque()) {
+        hwcl->blending = mPremultipliedAlpha ?
+                HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
+    }
+
+    // scaling is already applied in mTransformedBounds
+    hwcl->displayFrame.left   = mTransformedBounds.left;
+    hwcl->displayFrame.top    = mTransformedBounds.top;
+    hwcl->displayFrame.right  = mTransformedBounds.right;
+    hwcl->displayFrame.bottom = mTransformedBounds.bottom;
+    hwcl->visibleRegionScreen.rects =
+            reinterpret_cast<hwc_rect_t const *>(
+                    visibleRegionScreen.getArray(
+                            &hwcl->visibleRegionScreen.numRects));
 }
 
 void LayerBase::setPerFrameData(hwc_layer_t* hwcl) {
     hwcl->compositionType = HWC_FRAMEBUFFER;
     hwcl->handle = NULL;
+    hwcl->sourceCrop.left   = 0;
+    hwcl->sourceCrop.top    = 0;
+    hwcl->sourceCrop.right  = mTransformedBounds.width();
+    hwcl->sourceCrop.bottom = mTransformedBounds.height();
 }
 
 void LayerBase::setFiltering(bool filtering)
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 91fef22..09f8ff3 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -20,14 +20,18 @@
 import static android.content.Intent.EXTRA_UID;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.NetworkPolicy.LIMIT_DISABLED;
 import static android.net.NetworkPolicy.SNOOZE_NEVER;
+import static android.net.NetworkPolicy.WARNING_DISABLED;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
 import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
+import static android.net.NetworkPolicyManager.computeNextCycleBoundary;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
+import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT;
 import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
@@ -79,6 +83,7 @@
 import org.easymock.IAnswer;
 
 import java.io.File;
+import java.util.LinkedHashSet;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
@@ -402,7 +407,7 @@
         final NetworkPolicy policy = new NetworkPolicy(
                 sTemplateWifi, 5, 1024L, 1024L, SNOOZE_NEVER);
         final long actualCycle = computeLastCycleBoundary(currentTime, policy);
-        assertEquals(expectedCycle, actualCycle);
+        assertTimeEquals(expectedCycle, actualCycle);
     }
 
     public void testLastCycleBoundaryLastMonth() throws Exception {
@@ -413,7 +418,7 @@
         final NetworkPolicy policy = new NetworkPolicy(
                 sTemplateWifi, 20, 1024L, 1024L, SNOOZE_NEVER);
         final long actualCycle = computeLastCycleBoundary(currentTime, policy);
-        assertEquals(expectedCycle, actualCycle);
+        assertTimeEquals(expectedCycle, actualCycle);
     }
 
     public void testLastCycleBoundaryThisMonthFebruary() throws Exception {
@@ -424,18 +429,48 @@
         final NetworkPolicy policy = new NetworkPolicy(
                 sTemplateWifi, 30, 1024L, 1024L, SNOOZE_NEVER);
         final long actualCycle = computeLastCycleBoundary(currentTime, policy);
-        assertEquals(expectedCycle, actualCycle);
+        assertTimeEquals(expectedCycle, actualCycle);
     }
 
     public void testLastCycleBoundaryLastMonthFebruary() throws Exception {
         // assume cycle day of "30th" in february, which should clamp
         final long currentTime = parseTime("2007-03-14T00:00:00.000Z");
-        final long expectedCycle = parseTime("2007-03-01T00:00:00.000Z");
+        final long expectedCycle = parseTime("2007-02-28T23:59:59.000Z");
 
         final NetworkPolicy policy = new NetworkPolicy(
                 sTemplateWifi, 30, 1024L, 1024L, SNOOZE_NEVER);
         final long actualCycle = computeLastCycleBoundary(currentTime, policy);
-        assertEquals(expectedCycle, actualCycle);
+        assertTimeEquals(expectedCycle, actualCycle);
+    }
+
+    public void testNextCycleSane() throws Exception {
+        final NetworkPolicy policy = new NetworkPolicy(
+                sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER);
+        final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
+
+        // walk forwards, ensuring that cycle boundaries don't get stuck
+        long currentCycle = computeNextCycleBoundary(parseTime("2011-08-01T00:00:00.000Z"), policy);
+        for (int i = 0; i < 128; i++) {
+            long nextCycle = computeNextCycleBoundary(currentCycle, policy);
+            assertEqualsFuzzy(DAY_IN_MILLIS * 30, nextCycle - currentCycle, DAY_IN_MILLIS * 3);
+            assertUnique(seen, nextCycle);
+            currentCycle = nextCycle;
+        }
+    }
+
+    public void testLastCycleSane() throws Exception {
+        final NetworkPolicy policy = new NetworkPolicy(
+                sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER);
+        final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
+
+        // walk backwards, ensuring that cycle boundaries look sane
+        long currentCycle = computeLastCycleBoundary(parseTime("2011-08-04T00:00:00.000Z"), policy);
+        for (int i = 0; i < 128; i++) {
+            long lastCycle = computeLastCycleBoundary(currentCycle, policy);
+            assertEqualsFuzzy(DAY_IN_MILLIS * 30, currentCycle - lastCycle, DAY_IN_MILLIS * 3);
+            assertUnique(seen, lastCycle);
+            currentCycle = lastCycle;
+        }
     }
 
     public void testNetworkPolicyAppliedCycleLastMonth() throws Exception {
@@ -734,6 +769,32 @@
         }
     }
 
+    private static void assertTimeEquals(long expected, long actual) {
+        if (expected != actual) {
+            fail("expected " + formatTime(expected) + " but was actually " + formatTime(actual));
+        }
+    }
+
+    private static String formatTime(long millis) {
+        final Time time = new Time(Time.TIMEZONE_UTC);
+        time.set(millis);
+        return time.format3339(false);
+    }
+
+    private static void assertEqualsFuzzy(long expected, long actual, long fuzzy) {
+        final long low = expected - fuzzy;
+        final long high = expected + fuzzy;
+        if (actual < low || actual > high) {
+            fail("value " + actual + " is outside [" + low + "," + high + "]");
+        }
+    }
+
+    private static void assertUnique(LinkedHashSet<Long> seen, Long value) {
+        if (!seen.add(value)) {
+            fail("found duplicate time " + value + " in series " + seen.toString());
+        }
+    }
+
     private static void assertNotificationType(int expected, String actualTag) {
         assertEquals(
                 Integer.toString(expected), actualTag.substring(actualTag.lastIndexOf(':') + 1));
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index cf69fd5..8eb9cc3 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -25,6 +25,7 @@
 import static android.net.NetworkStats.IFACE_ALL;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
+import static android.net.NetworkStatsHistory.FIELD_ALL;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
 import static android.net.NetworkTemplate.buildTemplateWifi;
 import static android.net.TrafficStats.UID_REMOVED;
@@ -302,7 +303,7 @@
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
 
         // verify service recorded history
-        history = mService.getHistoryForNetwork(sTemplateWifi);
+        history = mService.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
         assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
         assertEquals(HOUR_IN_MILLIS, history.getBucketDuration());
         assertEquals(2, history.size());
@@ -319,7 +320,7 @@
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
 
         // verify identical stats, but spread across 4 buckets now
-        history = mService.getHistoryForNetwork(sTemplateWifi);
+        history = mService.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
         assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
         assertEquals(30 * MINUTE_IN_MILLIS, history.getBucketDuration());
         assertEquals(4, history.size());
@@ -631,14 +632,15 @@
 
     private void assertNetworkTotal(NetworkTemplate template, long rxBytes, long rxPackets,
             long txBytes, long txPackets, int operations) {
-        final NetworkStatsHistory history = mService.getHistoryForNetwork(template);
+        final NetworkStatsHistory history = mService.getHistoryForNetwork(template, FIELD_ALL);
         assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
                 txPackets, operations);
     }
 
     private void assertUidTotal(NetworkTemplate template, int uid, long rxBytes, long rxPackets,
             long txBytes, long txPackets, int operations) {
-        final NetworkStatsHistory history = mService.getHistoryForUid(template, uid, TAG_NONE);
+        final NetworkStatsHistory history = mService.getHistoryForUid(
+                template, uid, TAG_NONE, FIELD_ALL);
         assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
                 txPackets, operations);
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index 4d86903..134227a 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -484,8 +484,7 @@
         // Note: it needs to be confirmed which CDMA network types
         // can support voice and data calls concurrently.
         // For the time-being, the return value will be false.
-        // return (networkType >= ServiceState.RADIO_TECHNOLOGY_LTE);
-        return false;
+        return (networkType == ServiceState.RADIO_TECHNOLOGY_LTE);
     }
 
     /**
diff --git a/tests/BiDiTests/res/layout/basic.xml b/tests/BiDiTests/res/layout/basic.xml
index ed91c49..18f193e 100644
--- a/tests/BiDiTests/res/layout/basic.xml
+++ b/tests/BiDiTests/res/layout/basic.xml
@@ -34,17 +34,32 @@
                     android:textSize="32dip"
                     />
 
-            <TextView android:id="@+id/textview"
+            <TextView android:id="@+id/textview_ltr"
                       android:layout_height="wrap_content"
                       android:layout_width="wrap_content"
                       android:textSize="32dip"
-                      android:text="@string/textview_text"
+                      android:text="@string/textview_ltr_text"
                     />
 
-            <EditText android:id="@+id/edittext"
+            <EditText android:id="@+id/edittext_ltr"
                       android:layout_height="wrap_content"
                       android:layout_width="match_parent"
                       android:textSize="32dip"
+                      android:textDirection="ltr"
+                    />
+
+            <TextView android:id="@+id/textview_rtl"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="32dip"
+                      android:text="@string/textview_rtl_text"
+                    />
+
+            <EditText android:id="@+id/edittext_rtl"
+                      android:layout_height="wrap_content"
+                      android:layout_width="match_parent"
+                      android:textSize="32dip"
+                      android:textDirection="rtl"
                     />
 
         </LinearLayout>
diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml
index 1f6be7f..f4ce0f7 100644
--- a/tests/BiDiTests/res/values/strings.xml
+++ b/tests/BiDiTests/res/values/strings.xml
@@ -25,6 +25,8 @@
     <string name="button_requestlayout_text">Request Layout</string>
     <string name="button_alert_dialog_text">AlertDialog</string>
     <string name="textview_text">This is a text for a TextView</string>
+    <string name="textview_ltr_text">This is a text for a LTR TextView</string>
+    <string name="textview_rtl_text">This is a text for a RTL TextView</string>
     <string name="edittext_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
     <string name="normal_text">Normal String</string>
     <string name="normal_long_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
diff --git a/tests/GridLayoutTest/res/layout/grid3.xml b/tests/GridLayoutTest/res/layout/grid3.xml
index 2eca384..0e53613 100644
--- a/tests/GridLayoutTest/res/layout/grid3.xml
+++ b/tests/GridLayoutTest/res/layout/grid3.xml
@@ -22,6 +22,7 @@
 
         android:useDefaultMargins="true"
         android:alignmentMode="alignBounds"
+        android:rowOrderPreserved="false"
 
         android:columnCount="4"
         >
@@ -49,7 +50,7 @@
             />
 
     <EditText
-            android:layout_width="64dip"
+            android:ems="10"
             />
 
     <TextView
@@ -60,13 +61,13 @@
             />
 
     <EditText
-            android:layout_width="32dip"
+            android:ems="8"
             />
 
     <Space
-            android:layout_row="4"
+            android:layout_row="2"
+            android:layout_rowSpan="3"
             android:layout_column="2"
-            android:layout_margin="0dip"
             android:layout_gravity="fill"
             />
 
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
index 907ee9c..8974f37 100644
--- a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
@@ -38,7 +38,6 @@
         p.setUseDefaultMargins(true);
         p.setAlignmentMode(ALIGN_BOUNDS);
         p.setRowOrderPreserved(false);
-        p.setPadding(0, 0, 0, 0);
 
         Spec row1 = spec(0);
         Spec row2 = spec(1);
@@ -75,12 +74,9 @@
         }
         {
             EditText c = new EditText(context);
+            c.setEms(10);
             c.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
-            {
-                LayoutParams lp = new LayoutParams(row3, col2);
-                lp.width = (int) c.getPaint().measureText("Frederick.W.Flintstone");
-                p.addView(c, lp);
-            }
+            p.addView(c, new LayoutParams(row3, col2));
         }
         {
             TextView c = new TextView(context);
@@ -89,17 +85,13 @@
         }
         {
             TextView c = new EditText(context);
+            c.setEms(8);
             c.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD);
-            {
-                LayoutParams lp = new LayoutParams(row4, col2);
-                lp.width = (int) c.getPaint().measureText("************");
-                p.addView(c, lp);
-            }
+            p.addView(c, new LayoutParams(row4, col2));
         }
         {
             Space c = new Space(context);
             LayoutParams lp = new LayoutParams(row5, col3);
-            lp.setMargins(0, 0, 0, 0);
             p.addView(c, lp);
         }
         {
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
index 7bf25cf..4037a69 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
@@ -77,13 +77,23 @@
             super.onDraw(canvas);
             canvas.drawRGB(255, 255, 255);
 
+            mMediumPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+            mMediumPaint.setStrokeWidth(2.0f);
             canvas.drawText("Hello OpenGL renderer!", 100, 20, mMediumPaint);
+
+            mMediumPaint.setStyle(Paint.Style.FILL);
             mMediumPaint.setTextAlign(Paint.Align.CENTER);
             canvas.drawText("Hello OpenGL renderer!", 100, 40, mMediumPaint);
+
+            mMediumPaint.setStyle(Paint.Style.STROKE);
+            mMediumPaint.setStrokeWidth(2.0f);
             mMediumPaint.setTextAlign(Paint.Align.RIGHT);
             canvas.drawText("Hello OpenGL renderer!", 100, 60, mMediumPaint);
+
+            mMediumPaint.setStyle(Paint.Style.FILL);
             mMediumPaint.setTextAlign(Paint.Align.LEFT);
             canvas.drawText("Hello OpenGL renderer!", 100, 100, mMediumPaint);
+
             mMediumPaint.setShadowLayer(2.5f, 0.0f, 0.0f, 0xff000000);
             canvas.drawText("Hello OpenGL renderer!", 100, 150, mMediumPaint);
             mMediumPaint.clearShadowLayer();
diff --git a/tests/TileBenchmark/res/values/strings.xml b/tests/TileBenchmark/res/values/strings.xml
index 66972ac..c4fd189 100644
--- a/tests/TileBenchmark/res/values/strings.xml
+++ b/tests/TileBenchmark/res/values/strings.xml
@@ -71,8 +71,16 @@
     <string name="frames_per_second">Frames/sec</string>
     <!-- Portion of viewport covered by good tiles [CHAR LIMIT=15] -->
     <string name="viewport_coverage">Coverage</string>
+    <!-- Milliseconds taken to inval, and re-render the page [CHAR LIMIT=15] -->
+    <string name="render_millis">RenderMillis</string>
     <!-- Format string for stat value overlay [CHAR LIMIT=15] -->
     <string name="format_stat">%4.4f</string>
+
+    <!-- Format string for viewport position value overlay [CHAR LIMIT=25] -->
+    <string name="format_view_pos">View:(%1$d,%2$d)-(%3$d,%4$d)</string>
+    <!-- Format string for viewport position value overlay [CHAR LIMIT=25] -->
+    <string name="format_inval_pos">Inval:(%1$d,%2$d)-(%3$d,%4$d)</string>
+
     <!-- Format string for displaying aggregate stats+values (nr of valid tiles,
     etc.) [CHAR LIMIT=20] -->
     <string name="format_stat_name">%1$-20s %2$3d</string>
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java
index 36694a7..1eb1c00 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java
@@ -83,14 +83,14 @@
         }
     };
 
-    private class LoadFileTask extends AsyncTask<String, Void, TileData[][]> {
+    private class LoadFileTask extends AsyncTask<String, Void, RunData> {
         @Override
-        protected TileData[][] doInBackground(String... params) {
-            TileData[][] data = null;
+        protected RunData doInBackground(String... params) {
+            RunData data = null;
             try {
                 FileInputStream fis = openFileInput(params[0]);
                 ObjectInputStream in = new ObjectInputStream(fis);
-                data = (TileData[][]) in.readObject();
+                data = (RunData) in.readObject();
                 in.close();
             } catch (IOException ex) {
                 ex.printStackTrace();
@@ -101,7 +101,7 @@
         }
 
         @Override
-        protected void onPostExecute(TileData data[][]) {
+        protected void onPostExecute(RunData data) {
             if (data == null) {
                 Toast.makeText(getApplicationContext(),
                         getResources().getString(R.string.error_no_data),
@@ -110,7 +110,7 @@
             }
             mPlaybackView.setData(data);
 
-            mFrameMax = data.length - 1;
+            mFrameMax = data.frames.length - 1;
             mSeekBar.setMax(mFrameMax);
 
             setFrame(null, 0);
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
index 35b1563..9ea90f8 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
@@ -22,10 +22,12 @@
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.drawable.ShapeDrawable;
-import android.os.Bundle;
+
+import com.test.tilebenchmark.RunData.TileData;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 
 public class PlaybackGraphs {
     private static final int BAR_WIDTH = PlaybackView.TILE_SCALE * 3;
@@ -44,7 +46,7 @@
         return 0.0f;
     }
 
-    private interface MetricGen {
+    protected interface MetricGen {
         public double getValue(TileData[] frame);
 
         public double getMax();
@@ -52,7 +54,7 @@
         public int getLabelId();
     };
 
-    private static MetricGen[] Metrics = new MetricGen[] {
+    protected static MetricGen[] Metrics = new MetricGen[] {
             new MetricGen() {
                 // framerate graph
                 @Override
@@ -99,7 +101,7 @@
             }
     };
 
-    private interface StatGen {
+    protected interface StatGen {
         public double getValue(double sortedValues[]);
 
         public int getLabelId();
@@ -116,7 +118,7 @@
                 + sortedValues[intIndex + 1] * (alpha);
     }
 
-    private static StatGen[] Stats = new StatGen[] {
+    protected static StatGen[] Stats = new StatGen[] {
             new StatGen() {
                 @Override
                 public double getValue(double[] sortedValues) {
@@ -157,21 +159,22 @@
     }
 
     private ArrayList<ShapeDrawable> mShapes = new ArrayList<ShapeDrawable>();
-    private double[][] mStats = new double[Metrics.length][Stats.length];
+    protected double[][] mStats = new double[Metrics.length][Stats.length];
+    protected HashMap<String, Double> mSingleStats;
 
-    public void setData(TileData[][] tileProfilingData) {
+    public void setData(RunData data) {
         mShapes.clear();
-        double metricValues[] = new double[tileProfilingData.length];
+        double metricValues[] = new double[data.frames.length];
 
-        if (tileProfilingData.length == 0) {
+        if (data.frames.length == 0) {
             return;
         }
 
         for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
             // create graph out of rectangles, one per frame
             int lastBar = 0;
-            for (int frameIndex = 0; frameIndex < tileProfilingData.length; frameIndex++) {
-                TileData frame[] = tileProfilingData[frameIndex];
+            for (int frameIndex = 0; frameIndex < data.frames.length; frameIndex++) {
+                TileData frame[] = data.frames[frameIndex];
                 int newBar = (frame[0].top + frame[0].bottom) / 2;
 
                 MetricGen s = Metrics[metricIndex];
@@ -194,9 +197,11 @@
             // store aggregate statistics per metric (median, and similar)
             Arrays.sort(metricValues);
             for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
-                mStats[metricIndex][statIndex] = Stats[statIndex]
-                        .getValue(metricValues);
+                mStats[metricIndex][statIndex] =
+                        Stats[statIndex].getValue(metricValues);
             }
+
+            mSingleStats = data.singleStats;
         }
     }
 
@@ -215,7 +220,7 @@
     }
 
     public void draw(Canvas canvas, ArrayList<ShapeDrawable> shapes,
-            String[] strings, Resources resources) {
+            ArrayList<String> strings, Resources resources) {
         canvas.scale(CANVAS_SCALE, CANVAS_SCALE);
 
         canvas.translate(BAR_WIDTH * Metrics.length, 0);
@@ -231,33 +236,18 @@
             int yPos = LABELOFFSET;
             canvas.drawText(label, xPos, yPos, whiteLabels);
             for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
-                label = resources.getString(R.string.format_stat,
-                        mStats[metricIndex][statIndex]);
+                String statLabel = resources.getString(
+                        Stats[statIndex].getLabelId()).substring(0,3);
+                label = statLabel + " " + resources.getString(
+                        R.string.format_stat, mStats[metricIndex][statIndex]);
                 yPos = LABELOFFSET + (1 + statIndex) * PlaybackView.TILE_SCALE
                         / 2;
                 canvas.drawText(label, xPos, yPos, whiteLabels);
             }
         }
-        for (int stringIndex = 0; stringIndex < strings.length; stringIndex++) {
+        for (int stringIndex = 0; stringIndex < strings.size(); stringIndex++) {
             int yPos = LABELOFFSET + stringIndex * PlaybackView.TILE_SCALE / 2;
-            canvas.drawText(strings[stringIndex], 0, yPos, whiteLabels);
+            canvas.drawText(strings.get(stringIndex), 0, yPos, whiteLabels);
         }
     }
-
-    public Bundle getStatBundle(Resources resources) {
-        Bundle b = new Bundle();
-
-        for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
-            for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
-                String metricLabel = resources.getString(
-                        Metrics[metricIndex].getLabelId());
-                String statLabel = resources.getString(
-                        Stats[statIndex].getLabelId());
-                double value = mStats[metricIndex][statIndex];
-                b.putDouble(metricLabel + " " + statLabel, value);
-            }
-        }
-
-        return b;
-    }
 }
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java
index edc8643..5459c1f 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java
@@ -30,10 +30,12 @@
 import android.view.MotionEvent;
 import android.view.View;
 
+import com.test.tilebenchmark.RunData.TileData;
+
 import java.util.ArrayList;
 
 public class PlaybackView extends View {
-    public static final int TILE_SCALE = 300;
+    public static final int TILE_SCALE = 256;
     private static final int INVAL_FLAG = -2;
     private static final int INVAL_CYCLE = 250;
 
@@ -41,9 +43,9 @@
     private PlaybackGraphs mGraphs;
 
     private ArrayList<ShapeDrawable> mTempShapes = new ArrayList<ShapeDrawable>();
-    private TileData mProfData[][] = null;
+    private RunData mProfData = null;
     private GestureDetector mGestureDetector = null;
-    private String mRenderStrings[] = new String[4];
+    private ArrayList<String> mRenderStrings = new ArrayList<String>();
 
     private class TileDrawable extends ShapeDrawable {
         TileData tile;
@@ -135,17 +137,30 @@
         invalidate(); // may have animations, force redraw
     }
 
+    private String statString(int labelId, int value) {
+        return getResources().getString(R.string.format_stat_name,
+                getResources().getString(labelId), value);
+    }
+    private String tileString(int formatStringId, TileData t) {
+        return getResources().getString(formatStringId,
+                t.left, t.top, t.right, t.bottom);
+    }
+
     public int setFrame(int frame) {
-        if (mProfData == null || mProfData.length == 0) {
+        if (mProfData == null || mProfData.frames.length == 0) {
             return 0;
         }
 
         int readyTiles = 0, unreadyTiles = 0, unplacedTiles = 0, numInvals = 0;
         mTempShapes.clear();
+        mRenderStrings.clear();
 
         // create tile shapes (as they're drawn on bottom)
-        for (TileData t : mProfData[frame]) {
-            if (t.level != INVAL_FLAG && t != mProfData[frame][0]) {
+        for (TileData t : mProfData.frames[frame]) {
+            if (t == mProfData.frames[frame][0]){
+                // viewport 'tile', add coords to render strings
+                mRenderStrings.add(tileString(R.string.format_view_pos, t));
+            } else  if (t.level != INVAL_FLAG) {
                 int colorId;
                 if (t.isReady) {
                     readyTiles++;
@@ -159,14 +174,16 @@
                 }
                 mTempShapes.add(new TileDrawable(t, colorId));
             } else {
+                // inval 'tile', count and add coords to render strings
                 numInvals++;
+                mRenderStrings.add(tileString(R.string.format_inval_pos, t));
             }
         }
 
         // create invalidate shapes (drawn above tiles)
         int invalId = 0;
-        for (TileData t : mProfData[frame]) {
-            if (t.level == INVAL_FLAG && t != mProfData[frame][0]) {
+        for (TileData t : mProfData.frames[frame]) {
+            if (t.level == INVAL_FLAG && t != mProfData.frames[frame][0]) {
                 TileDrawable invalShape = new TileDrawable(t,
                         R.color.inval_region_start);
                 ValueAnimator tileAnimator = ObjectAnimator.ofInt(invalShape,
@@ -186,26 +203,20 @@
             }
         }
 
-        mRenderStrings[0] = getResources().getString(R.string.format_stat_name,
-                getResources().getString(R.string.ready_tiles), readyTiles);
-        mRenderStrings[1] = getResources().getString(R.string.format_stat_name,
-                getResources().getString(R.string.unready_tiles), unreadyTiles);
-        mRenderStrings[2] = getResources().getString(R.string.format_stat_name,
-                getResources().getString(R.string.unplaced_tiles),
-                unplacedTiles);
-        mRenderStrings[3] = getResources().getString(R.string.format_stat_name,
-                getResources().getString(R.string.number_invalidates),
-                numInvals);
+        mRenderStrings.add(statString(R.string.ready_tiles, readyTiles));
+        mRenderStrings.add(statString(R.string.unready_tiles, unreadyTiles));
+        mRenderStrings.add(statString(R.string.unplaced_tiles, unplacedTiles));
+        mRenderStrings.add(statString(R.string.number_invalidates, numInvals));
 
         // draw view rect (using first TileData object, on top)
-        TileDrawable viewShape = new TileDrawable(mProfData[frame][0],
+        TileDrawable viewShape = new TileDrawable(mProfData.frames[frame][0],
                 R.color.view);
         mTempShapes.add(viewShape);
         this.invalidate();
         return frame;
     }
 
-    public void setData(TileData[][] tileProfilingData) {
+    public void setData(RunData tileProfilingData) {
         mProfData = tileProfilingData;
 
         mGraphs.setData(mProfData);
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
index 1521807..82a7e82 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
@@ -51,11 +51,11 @@
 public class ProfileActivity extends Activity {
 
     public interface ProfileCallback {
-        public void profileCallback(TileData data[][]);
+        public void profileCallback(RunData data);
     }
 
     public static final String TEMP_FILENAME = "profile.tiles";
-    private static final int LOAD_TEST_DELAY = 2000; // nr of millis after load,
+    private static final int LOAD_TEST_DELAY = 1000; // nr of millis after load,
                                                      // before test
 
     Button mInspectButton;
@@ -135,6 +135,7 @@
         public void onPageFinished(WebView view, String url) {
             super.onPageFinished(view, url);
             view.requestFocus();
+
             new CountDownTimer(LOAD_TEST_DELAY, LOAD_TEST_DELAY) {
                 @Override
                 public void onTick(long millisUntilFinished) {
@@ -155,10 +156,10 @@
     }
 
     private class StoreFileTask extends
-            AsyncTask<Pair<String, TileData[][]>, Void, Void> {
+            AsyncTask<Pair<String, RunData>, Void, Void> {
 
         @Override
-        protected Void doInBackground(Pair<String, TileData[][]>... params) {
+        protected Void doInBackground(Pair<String, RunData>... params) {
             try {
                 FileOutputStream fos = openFileOutput(params[0].first,
                         Context.MODE_PRIVATE);
@@ -205,10 +206,8 @@
 
     /** auto - automatically scroll. */
     private void startViewProfiling(boolean auto) {
-        if (!auto) {
-            // manual, toggle capture button to indicate capture state to user
-            mCaptureButton.setChecked(true);
-        }
+        // toggle capture button to indicate capture state to user
+        mCaptureButton.setChecked(true);
         mWeb.startScrollTest(mCallback, auto);
         setTestingState(TestingState.START_TESTING);
     }
@@ -224,16 +223,16 @@
         mMovementSpinner = (Spinner) findViewById(R.id.movement);
         mUrl = (EditText) findViewById(R.id.url);
         mWeb = (ProfiledWebView) findViewById(R.id.web);
-        mCallback = new ProfileCallback() {
+        setCallback(new ProfileCallback() {
             @SuppressWarnings("unchecked")
             @Override
-            public void profileCallback(TileData[][] data) {
-                new StoreFileTask().execute(new Pair<String, TileData[][]>(
+            public void profileCallback(RunData data) {
+                new StoreFileTask().execute(new Pair<String, RunData>(
                         TEMP_FILENAME, data));
                 mCaptureButton.setChecked(false);
                 setTestingState(TestingState.STOP_TESTING);
             }
-        };
+        });
 
         // Inspect button (opens PlaybackActivity)
         mInspectButton.setOnClickListener(new OnClickListener() {
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
index d3941be..3fc4665 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
@@ -18,15 +18,19 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.webkit.WebView;
 
 import com.test.tilebenchmark.ProfileActivity.ProfileCallback;
+import com.test.tilebenchmark.RunData.TileData;
 
 public class ProfiledWebView extends WebView {
     private int mSpeed;
 
+    private boolean isTesting = false;
     private boolean isScrolling = false;
     private ProfileCallback mCallback;
+    private long mContentInvalMillis;
 
     public ProfiledWebView(Context context) {
         super(context);
@@ -47,7 +51,7 @@
 
     @Override
     protected void onDraw(android.graphics.Canvas canvas) {
-        if (isScrolling) {
+        if (isTesting && isScrolling) {
             if (canScrollVertically(1)) {
                 scrollBy(0, mSpeed);
             } else {
@@ -60,31 +64,53 @@
 
     /*
      * Called once the page is loaded to start scrolling for evaluating tiles.
-     * If autoScrolling isn't set, stop must be called manually.
+     * If autoScrolling isn't set, stop must be called manually. Before
+     * scrolling, invalidate all content and redraw it, measuring time taken.
      */
     public void startScrollTest(ProfileCallback callback, boolean autoScrolling) {
         isScrolling = autoScrolling;
         mCallback = callback;
-        tileProfilingStart();
+        isTesting = false;
+        mContentInvalMillis = System.currentTimeMillis();
+        registerPageSwapCallback();
+        contentInvalidateAll();
         invalidate();
     }
 
     /*
+     * Called after the manual contentInvalidateAll, after the tiles have all
+     * been redrawn.
+     */
+    @Override
+    protected void pageSwapCallback() {
+        mContentInvalMillis = System.currentTimeMillis() - mContentInvalMillis;
+        super.pageSwapCallback();
+        Log.d("ProfiledWebView", "REDRAW TOOK " + mContentInvalMillis
+                + "millis");
+        isTesting = true;
+        invalidate(); // ensure a redraw so that auto-scrolling can occur
+        tileProfilingStart();
+    }
+
+    /*
      * Called once the page has stopped scrolling
      */
     public void stopScrollTest() {
-        super.tileProfilingStop();
+        tileProfilingStop();
+        isTesting = false;
 
         if (mCallback == null) {
             tileProfilingClear();
             return;
         }
 
-        TileData data[][] = new TileData[super.tileProfilingNumFrames()][];
-        for (int frame = 0; frame < data.length; frame++) {
-            data[frame] = new TileData[
+        RunData data = new RunData(super.tileProfilingNumFrames());
+        data.singleStats.put(getResources().getString(R.string.render_millis),
+                (double)mContentInvalMillis);
+        for (int frame = 0; frame < data.frames.length; frame++) {
+            data.frames[frame] = new TileData[
                     tileProfilingNumTilesInFrame(frame)];
-            for (int tile = 0; tile < data[frame].length; tile++) {
+            for (int tile = 0; tile < data.frames[frame].length; tile++) {
                 int left = tileProfilingGetInt(frame, tile, "left");
                 int top = tileProfilingGetInt(frame, tile, "top");
                 int right = tileProfilingGetInt(frame, tile, "right");
@@ -96,18 +122,18 @@
 
                 float scale = tileProfilingGetFloat(frame, tile, "scale");
 
-                data[frame][tile] = new TileData(left, top, right, bottom,
+                data.frames[frame][tile] = data.new TileData(left, top, right, bottom,
                         isReady, level, scale);
             }
         }
-        super.tileProfilingClear();
+        tileProfilingClear();
 
         mCallback.profileCallback(data);
     }
 
     @Override
     public void loadUrl(String url) {
-        if (!url.startsWith("http://")) {
+        if (!url.startsWith("http://") && !url.startsWith("file://")) {
             url = "http://" + url;
         }
         super.loadUrl(url);
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/RunData.java b/tests/TileBenchmark/src/com/test/tilebenchmark/RunData.java
new file mode 100644
index 0000000..2da61cc
--- /dev/null
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/RunData.java
@@ -0,0 +1,53 @@
+/*
+ * 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.test.tilebenchmark;
+
+import java.io.Serializable;
+import java.util.HashMap;
+
+public class RunData implements Serializable {
+    public TileData[][] frames;
+    public HashMap<String, Double> singleStats = new HashMap<String, Double>();
+
+    public RunData(int frames) {
+        this.frames = new TileData[frames][];
+    }
+
+    public class TileData implements Serializable {
+        public int left, top, right, bottom;
+        public boolean isReady;
+        public int level;
+        public float scale;
+
+        public TileData(int left, int top, int right, int bottom,
+                boolean isReady, int level, float scale) {
+            this.left = left;
+            this.right = right;
+            this.top = top;
+            this.bottom = bottom;
+            this.isReady = isReady;
+            this.level = level;
+            this.scale = scale;
+        }
+
+        public String toString() {
+            return "Tile (" + left + "," + top + ")->("
+                    + right + "," + bottom + ")";
+        }
+    }
+
+}
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java b/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java
deleted file mode 100644
index 3e729a6..0000000
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java
+++ /dev/null
@@ -1,42 +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.test.tilebenchmark;
-
-import java.io.Serializable;
-
-public class TileData implements Serializable {
-    int left, top, right, bottom;
-    public boolean isReady;
-    public int level;
-    public float scale;
-
-    public TileData(int left, int top, int right, int bottom, boolean isReady,
-            int level, float scale) {
-        this.left = left;
-        this.right = right;
-        this.top = top;
-        this.bottom = bottom;
-        this.isReady = isReady;
-        this.level = level;
-        this.scale = scale;
-    }
-
-    public String toString() {
-        return "Tile (" + left + "," + top + ")->("
-                + right + "," + bottom + ")";
-    }
-}
diff --git a/tests/TileBenchmark/tests/Android.mk b/tests/TileBenchmark/tests/Android.mk
new file mode 100644
index 0000000..8b235ec
--- /dev/null
+++ b/tests/TileBenchmark/tests/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := TileBenchmarkTests
+
+LOCAL_INSTRUMENTATION_FOR := TileBenchmark
+
+include $(BUILD_PACKAGE)
diff --git a/tests/TileBenchmark/tests/AndroidManifest.xml b/tests/TileBenchmark/tests/AndroidManifest.xml
new file mode 100644
index 0000000..703b152
--- /dev/null
+++ b/tests/TileBenchmark/tests/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.test.tilebenchmark.tests">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.test.tilebenchmark"
+                     android:label="Tests for WebView Tiles."/>
+</manifest>
diff --git a/tests/TileBenchmark/tests/src/com/test/tilebenchmark/PerformanceTest.java b/tests/TileBenchmark/tests/src/com/test/tilebenchmark/PerformanceTest.java
new file mode 100644
index 0000000..0f02239
--- /dev/null
+++ b/tests/TileBenchmark/tests/src/com/test/tilebenchmark/PerformanceTest.java
@@ -0,0 +1,167 @@
+/*
+ * 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.test.tilebenchmark;
+
+import com.test.tilebenchmark.ProfileActivity.ProfileCallback;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Environment;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+public class PerformanceTest extends
+        ActivityInstrumentationTestCase2<ProfileActivity> {
+
+    private class StatAggregator extends PlaybackGraphs {
+        private HashMap<String, Double> mDataMap = new HashMap<String, Double>();
+        private int mCount = 0;
+
+        public void aggregate() {
+            mCount++;
+            Resources resources = mView.getResources();
+            for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
+                for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
+                    String metricLabel = resources.getString(
+                            Metrics[metricIndex].getLabelId());
+                    String statLabel = resources.getString(
+                            Stats[statIndex].getLabelId());
+
+                    String label = metricLabel + " " + statLabel;
+                    double aggVal = mDataMap.containsKey(label) ? mDataMap
+                            .get(label) : 0;
+
+                    aggVal += mStats[metricIndex][statIndex];
+                    mDataMap.put(label, aggVal);
+                }
+            }
+            for (Map.Entry<String, Double> e : mSingleStats.entrySet()) {
+                double aggVal = mDataMap.containsKey(e.getKey())
+                        ? mDataMap.get(e.getKey()) : 0;
+                mDataMap.put(e.getKey(), aggVal + e.getValue());
+            }
+        }
+
+        public Bundle getBundle() {
+            Bundle b = new Bundle();
+            int count = 0 == mCount ? Integer.MAX_VALUE : mCount;
+            for (Map.Entry<String, Double> e : mDataMap.entrySet()) {
+                b.putDouble(e.getKey(), e.getValue() / count);
+            }
+            return b;
+        }
+    }
+
+    ProfileActivity mActivity;
+    ProfiledWebView mView;
+    StatAggregator mStats = new StatAggregator();
+
+    private static final String LOGTAG = "PerformanceTest";
+    private static final String TEST_LOCATION = "webkit/page_cycler";
+    private static final String URL_PREFIX = "file://";
+    private static final String URL_POSTFIX = "/index.html?skip=true";
+    private static final int MAX_ITERATIONS = 4;
+    private static final String TEST_DIRS[] = {
+            "alexa_us"//, "android", "dom", "intl1", "intl2", "moz", "moz2"
+    };
+
+    public PerformanceTest() {
+        super(ProfileActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+        mView = (ProfiledWebView) mActivity.findViewById(R.id.web);
+    }
+
+    private boolean loadUrl(final String url) {
+        try {
+            Log.d(LOGTAG, "test starting for url " + url);
+            mActivity.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    mView.loadUrl(url);
+                }
+            });
+            synchronized (mStats) {
+                mStats.wait();
+            }
+            mStats.aggregate();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+            return false;
+        }
+        return true;
+    }
+
+    private boolean runIteration() {
+        File sdFile = Environment.getExternalStorageDirectory();
+        for (String testDirName : TEST_DIRS) {
+            File testDir = new File(sdFile, TEST_LOCATION + "/" + testDirName);
+            Log.d(LOGTAG, "Testing dir: '" + testDir.getAbsolutePath()
+                    + "', exists=" + testDir.exists());
+            for (File siteDir : testDir.listFiles()) {
+                if (!siteDir.isDirectory())
+                    continue;
+
+                if (!loadUrl(URL_PREFIX + siteDir.getAbsolutePath()
+                        + URL_POSTFIX)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    public void testMetrics() {
+        String state = Environment.getExternalStorageState();
+
+        if (!Environment.MEDIA_MOUNTED.equals(state)
+                && !Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
+            Log.d(LOGTAG, "ARG Can't access sd card!");
+            // Can't read the SD card, fail and die!
+            getInstrumentation().sendStatus(1, null);
+            return;
+        }
+
+        // use mGraphs as a condition variable between the UI thread and
+        // this(the testing) thread
+        mActivity.setCallback(new ProfileCallback() {
+            @Override
+            public void profileCallback(RunData data) {
+                Log.d(LOGTAG, "test completion callback");
+                mStats.setData(data);
+                synchronized (mStats) {
+                    mStats.notify();
+                }
+            }
+        });
+
+        for (int i = 0; i < MAX_ITERATIONS; i++)
+            if (!runIteration()) {
+                getInstrumentation().sendStatus(1, null);
+                return;
+            }
+        getInstrumentation().sendStatus(0, mStats.getBundle());
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
index 625b40d..0928ec5 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
@@ -417,6 +417,22 @@
     }
 
     @Override
+    public boolean getBoolean(int id) throws NotFoundException {
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
+
+        if (value != null && value.getSecond().getValue() != null) {
+            String v = value.getSecond().getValue();
+            return Boolean.parseBoolean(v);
+        }
+
+        // id was not found or not resolved. Throw a NotFoundException.
+        throwException(id);
+
+        // this is not used since the method above always throws
+        return false;
+    }
+
+    @Override
     public String getResourceEntryName(int resid) throws NotFoundException {
         throw new UnsupportedOperationException();
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
index d94f369..5952c37 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -28,6 +28,7 @@
 import android.util.DisplayMetrics;
 import android.view.Display;
 import android.view.Display_Delegate;
+import android.view.Gravity;
 import android.view.IApplicationToken;
 import android.view.IOnKeyguardExitResult;
 import android.view.IRotationWatcher;
@@ -455,4 +456,9 @@
         return null;
     }
 
+    @Override
+    public int getPreferredOptionsPanelGravity() throws RemoteException {
+        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+    }
+
 }
diff --git a/wifi/java/android/net/wifi/SupplicantStateTracker.java b/wifi/java/android/net/wifi/SupplicantStateTracker.java
index 9168e62..cbd284c 100644
--- a/wifi/java/android/net/wifi/SupplicantStateTracker.java
+++ b/wifi/java/android/net/wifi/SupplicantStateTracker.java
@@ -89,7 +89,7 @@
             mNetworksDisabledDuringConnect = false;
         }
         /* Disable failed network */
-        WifiConfigStore.disableNetwork(netId);
+        WifiConfigStore.disableNetwork(netId, WifiConfiguration.DISABLED_AUTH_FAILURE);
     }
 
     private void transitionOnSupplicantStateChange(StateChangeResult stateChangeResult) {
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index d83b968..9a51d5e 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -195,8 +195,9 @@
      * or a failure event from supplicant
      *
      * @param config The configuration details in WifiConfiguration
+     * @return the networkId now associated with the specified configuration
      */
-    static void selectNetwork(WifiConfiguration config) {
+    static int selectNetwork(WifiConfiguration config) {
         if (config != null) {
             NetworkUpdateResult result = addOrUpdateNetworkNative(config);
             int netId = result.getNetworkId();
@@ -205,7 +206,9 @@
             } else {
                 Log.e(TAG, "Failed to update network " + config);
             }
+            return netId;
         }
+        return INVALID_NETWORK_ID;
     }
 
     /**
@@ -351,10 +354,22 @@
      * @param netId network to be disabled
      */
     static boolean disableNetwork(int netId) {
+        return disableNetwork(netId, WifiConfiguration.DISABLED_UNKNOWN_REASON);
+    }
+
+    /**
+     * Disable a network. Note that there is no saveConfig operation.
+     * @param netId network to be disabled
+     * @param reason reason code network was disabled
+     */
+    static boolean disableNetwork(int netId, int reason) {
         boolean ret = WifiNative.disableNetworkCommand(netId);
         synchronized (sConfiguredNetworks) {
             WifiConfiguration config = sConfiguredNetworks.get(netId);
-            if (config != null) config.status = Status.DISABLED;
+            if (config != null) {
+                config.status = Status.DISABLED;
+                config.disableReason = reason;
+            }
         }
         sendConfiguredNetworksChangedBroadcast();
         return ret;
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 28a5bc6..d2a0b30 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -211,6 +211,15 @@
         public static final String[] strings = { "current", "disabled", "enabled" };
     }
 
+    /** @hide */
+    public static final int DISABLED_UNKNOWN_REASON                         = 0;
+    /** @hide */
+    public static final int DISABLED_DNS_FAILURE                            = 1;
+    /** @hide */
+    public static final int DISABLED_DHCP_FAILURE                           = 2;
+    /** @hide */
+    public static final int DISABLED_AUTH_FAILURE                           = 3;
+
     /**
      * The ID number that the supplicant uses to identify this
      * network configuration entry. This must be passed as an argument
@@ -223,6 +232,14 @@
      * @see Status
      */
     public int status;
+
+    /**
+     * The code referring to a reason for disabling the network
+     * Valid when {@link #status} == Status.DISABLED
+     * @hide
+     */
+    public int disableReason;
+
     /**
      * The network's SSID. Can either be an ASCII string,
      * which must be enclosed in double quotation marks
@@ -351,6 +368,7 @@
         BSSID = null;
         priority = 0;
         hiddenSSID = false;
+        disableReason = DISABLED_UNKNOWN_REASON;
         allowedKeyManagement = new BitSet();
         allowedProtocols = new BitSet();
         allowedAuthAlgorithms = new BitSet();
@@ -367,12 +385,13 @@
         linkProperties = new LinkProperties();
     }
 
+    @Override
     public String toString() {
-        StringBuffer sbuf = new StringBuffer();
+        StringBuilder sbuf = new StringBuilder();
         if (this.status == WifiConfiguration.Status.CURRENT) {
             sbuf.append("* ");
         } else if (this.status == WifiConfiguration.Status.DISABLED) {
-            sbuf.append("- ");
+            sbuf.append("- DSBLE: ").append(this.disableReason).append(" ");
         }
         sbuf.append("ID: ").append(this.networkId).append(" SSID: ").append(this.SSID).
                 append(" BSSID: ").append(this.BSSID).append(" PRIO: ").append(this.priority).
@@ -541,6 +560,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(networkId);
         dest.writeInt(status);
+        dest.writeInt(disableReason);
         dest.writeString(SSID);
         dest.writeString(BSSID);
         dest.writeString(preSharedKey);
@@ -571,6 +591,7 @@
                 WifiConfiguration config = new WifiConfiguration();
                 config.networkId = in.readInt();
                 config.status = in.readInt();
+                config.disableReason = in.readInt();
                 config.SSID = in.readString();
                 config.BSSID = in.readString();
                 config.preSharedKey = in.readString();
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 7bb927b..d5b404e 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -70,6 +70,7 @@
     private InetAddress mIpAddress;
 
     private String mMacAddress;
+    private boolean mExplicitConnect;
 
     WifiInfo() {
         mSSID = null;
@@ -79,6 +80,7 @@
         mRssi = -9999;
         mLinkSpeed = -1;
         mHiddenSSID = false;
+        mExplicitConnect = false;
     }
 
     /**
@@ -96,6 +98,7 @@
             mLinkSpeed = source.mLinkSpeed;
             mIpAddress = source.mIpAddress;
             mMacAddress = source.mMacAddress;
+            mExplicitConnect = source.mExplicitConnect;
         }
     }
 
@@ -172,6 +175,22 @@
         mNetworkId = id;
     }
 
+
+    /**
+     * @hide
+     */
+    public boolean isExplicitConnect() {
+        return mExplicitConnect;
+    }
+
+    /**
+     * @hide
+     */
+    public void setExplicitConnect(boolean explicitConnect) {
+        this.mExplicitConnect = explicitConnect;
+    }
+
+
     /**
      * Each configured network has a unique small integer ID, used to identify
      * the network when performing operations on the supplicant. This method
@@ -260,7 +279,8 @@
             append(mSupplicantState == null ? none : mSupplicantState).
             append(", RSSI: ").append(mRssi).
             append(", Link speed: ").append(mLinkSpeed).
-            append(", Net ID: ").append(mNetworkId);
+            append(", Net ID: ").append(mNetworkId).
+            append(", Explicit connect: ").append(mExplicitConnect);
 
         return sb.toString();
     }
@@ -284,6 +304,7 @@
         dest.writeString(getSSID());
         dest.writeString(mBSSID);
         dest.writeString(mMacAddress);
+        dest.writeByte(mExplicitConnect ? (byte)1 : (byte)0);
         mSupplicantState.writeToParcel(dest, flags);
     }
 
@@ -303,6 +324,7 @@
                 info.setSSID(in.readString());
                 info.mBSSID = in.readString();
                 info.mMacAddress = in.readString();
+                info.mExplicitConnect = in.readByte() == 1 ? true : false;
                 info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in);
                 return info;
             }
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index cd6621f..5f8385c 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -615,6 +615,17 @@
     }
 
     /**
+     * Disable a configured network asynchronously.  This call is for abnormal network
+     * events, and the user may be notified of network change, if they recently attempted
+     * to connect to the specified network.
+     * @param netId the ID of the network as returned by {@link #addNetwork}.
+     * @hide
+     */
+    public void disableNetwork(int netId, int reason) {
+        mAsyncChannel.sendMessage(CMD_DISABLE_NETWORK, netId, reason);
+    }
+
+    /**
      * Disassociate from the currently active access point. This may result
      * in the asynchronous delivery of state change events.
      * @return {@code true} if the operation succeeded
@@ -1058,6 +1069,8 @@
     public static final int CMD_SAVE_NETWORK                = 3;
     /** @hide */
     public static final int CMD_START_WPS                   = 4;
+    /** @hide */
+    public static final int CMD_DISABLE_NETWORK             = 5;
 
     /* Events from WifiService */
     /** @hide */
@@ -1617,4 +1630,4 @@
              return false;
         }
     }
-}
+}
\ No newline at end of file
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index de49eb4..82ff0de 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -57,6 +57,7 @@
 import android.net.NetworkUtils;
 import android.net.wifi.WpsResult.Status;
 import android.net.wifi.p2p.WifiP2pManager;
+import android.net.wifi.p2p.WifiP2pService;
 import android.net.wifi.StateChangeResult;
 import android.os.Binder;
 import android.os.IBinder;
@@ -67,13 +68,14 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.WorkSource;
-import android.server.WifiP2pService;
 import android.provider.Settings;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.LruCache;
+import android.util.Slog;
 
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.AsyncChannel;
@@ -482,6 +484,11 @@
     private final WorkSource mLastRunningWifiUids = new WorkSource();
 
     private final IBatteryStats mBatteryStats;
+    private boolean mNextWifiActionExplicit = false;
+    private int mLastExplicitNetworkId;
+    private long mLastNetworkChoiceTime;
+    private static final long EXPLICIT_CONNECT_ALLOWED_DELAY_MS = 2 * 60 * 1000;
+
 
     public WifiStateMachine(Context context, String wlanInterface) {
         super(TAG);
@@ -821,7 +828,8 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public boolean syncDisableNetwork(AsyncChannel channel, int netId) {
-        Message resultMsg = channel.sendMessageSynchronously(CMD_DISABLE_NETWORK, netId);
+        Message resultMsg = channel.sendMessageSynchronously(CMD_DISABLE_NETWORK, netId,
+                WifiConfiguration.DISABLED_UNKNOWN_REASON);
         boolean result = (resultMsg.arg1 != FAILURE);
         resultMsg.recycle();
         return result;
@@ -866,6 +874,12 @@
         sendMessage(obtainMessage(CMD_FORGET_NETWORK, netId, 0));
     }
 
+    public void disableNetwork(Messenger replyTo, int netId, int reason) {
+        Message message = obtainMessage(CMD_DISABLE_NETWORK, netId, reason);
+        message.replyTo = replyTo;
+        sendMessage(message);
+    }
+
     public void startWps(Messenger replyTo, WpsConfiguration config) {
         Message msg = obtainMessage(CMD_START_WPS, config);
         msg.replyTo = replyTo;
@@ -1534,6 +1548,7 @@
         mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
         mWifiInfo.setRssi(MIN_RSSI);
         mWifiInfo.setLinkSpeed(-1);
+        mWifiInfo.setExplicitConnect(false);
 
         /* send event to CM & network change broadcast */
         setNetworkDetailedState(DetailedState.DISCONNECTED);
@@ -1631,7 +1646,8 @@
         if (++mReconnectCount > getMaxDhcpRetries()) {
             Log.e(TAG, "Failed " +
                     mReconnectCount + " times, Disabling " + mLastNetworkId);
-            WifiConfigStore.disableNetwork(mLastNetworkId);
+            WifiConfigStore.disableNetwork(mLastNetworkId,
+                    WifiConfiguration.DISABLED_DHCP_FAILURE);
             mReconnectCount = 0;
         }
 
@@ -2169,7 +2185,7 @@
                     WifiConfigStore.enableAllNetworks();
                     break;
                 case CMD_DISABLE_NETWORK:
-                    ok = WifiConfigStore.disableNetwork(message.arg1);
+                    ok = WifiConfigStore.disableNetwork(message.arg1, message.arg2);
                     mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
                     break;
                 case CMD_BLACKLIST_NETWORK:
@@ -2605,7 +2621,7 @@
                      * a connection to the enabled network.
                      */
                     if (config != null) {
-                        WifiConfigStore.selectNetwork(config);
+                        netId = WifiConfigStore.selectNetwork(config);
                     } else {
                         WifiConfigStore.selectNetwork(netId);
                     }
@@ -2614,7 +2630,10 @@
                     mSupplicantStateTracker.sendMessage(CMD_CONNECT_NETWORK);
 
                     WifiNative.reconnectCommand();
-
+                    mLastExplicitNetworkId = netId;
+                    mLastNetworkChoiceTime  = SystemClock.elapsedRealtime();
+                    mNextWifiActionExplicit = true;
+                    Slog.d(TAG, "Setting wifi connect explicit for netid " + netId);
                     /* Expect a disconnection from the old connection */
                     transitionTo(mDisconnectingState);
                     break;
@@ -2636,6 +2655,13 @@
                     mWifiInfo.setSSID(fetchSSID());
                     mWifiInfo.setBSSID(mLastBssid);
                     mWifiInfo.setNetworkId(mLastNetworkId);
+                    if (mNextWifiActionExplicit &&
+                        mWifiInfo.getNetworkId() == mLastExplicitNetworkId &&
+                        SystemClock.elapsedRealtime() < mLastNetworkChoiceTime +
+                                                            EXPLICIT_CONNECT_ALLOWED_DELAY_MS) {
+                        mWifiInfo.setExplicitConnect(true);
+                    }
+                    mNextWifiActionExplicit = false;
                     /* send event to CM & network change broadcast */
                     setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
                     sendNetworkStateChangeBroadcast(mLastBssid);
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index be9dfcf..5c8926c 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -44,9 +44,11 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.net.HttpURLConnection;
+import java.net.InetAddress;
 import java.net.URL;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * {@link WifiWatchdogStateMachine} monitors the initial connection to a Wi-Fi
@@ -68,6 +70,7 @@
     private static final boolean VDBG = false;
     private static final boolean DBG = true;
     private static final String WWSM_TAG = "WifiWatchdogStateMachine";
+    private static final String WATCHDOG_NOTIFICATION_ID = "Android.System.WifiWatchdog";
 
     private static final int WIFI_SIGNAL_LEVELS = 4;
     /**
@@ -82,7 +85,6 @@
     private static final int DEFAULT_MAX_SSID_BLACKLISTS = 7;
     private static final int DEFAULT_NUM_DNS_PINGS = 5;
     private static final int DEFAULT_MIN_DNS_RESPONSES = 3;
-    private static final long DNS_PING_INTERVAL_MS = 100;
 
     private static final int DEFAULT_DNS_PING_TIMEOUT_MS = 2000;
 
@@ -92,6 +94,7 @@
     private static final String DEFAULT_WALLED_GARDEN_URL =
             "http://clients3.google.com/generate_204";
     private static final int WALLED_GARDEN_SOCKET_TIMEOUT_MS = 10000;
+    private static final int DNS_INTRATEST_PING_INTERVAL = 20;
 
     private static final int BASE = Protocol.BASE_WIFI_WATCHDOG;
 
@@ -114,9 +117,8 @@
     private static final int EVENT_WIFI_RADIO_STATE_CHANGE = BASE + 5;
     private static final int EVENT_WATCHDOG_SETTINGS_CHANGE = BASE + 6;
 
-    private static final int MESSAGE_CHECK_STEP = BASE + 100;
-    private static final int MESSAGE_HANDLE_WALLED_GARDEN = BASE + 101;
-    private static final int MESSAGE_HANDLE_BAD_AP = BASE + 102;
+    private static final int MESSAGE_HANDLE_WALLED_GARDEN = BASE + 100;
+    private static final int MESSAGE_HANDLE_BAD_AP = BASE + 101;
     /**
      * arg1 == mOnlineWatchState.checkCount
      */
@@ -156,7 +158,7 @@
     /**
      * The {@link WifiInfo} object passed to WWSM on network broadcasts
      */
-    private WifiInfo mInitialConnInfo;
+    private WifiInfo mConnectionInfo;
     private int mNetEventCounter = 0;
 
     /**
@@ -172,7 +174,9 @@
      * It triggers a disableNetwork call if a DNS check fails.
      */
     public boolean mDisableAPNextFailure = false;
-    public ConnectivityManager mConnectivityManager;
+    private ConnectivityManager mConnectivityManager;
+    private boolean mNotificationShown;
+    public boolean mHasConnectedWifiManager = false;
 
     /**
      * STATE MAP
@@ -189,8 +193,9 @@
         mContext = context;
         mContentResolver = context.getContentResolver();
         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
-        mDnsPinger = new DnsPinger("WifiWatchdogServer.DnsPinger", context,
-                ConnectivityManager.TYPE_WIFI);
+        mDnsPinger = new DnsPinger(mContext, "WifiWatchdogStateMachine.DnsPinger",
+                                this.getHandler().getLooper(), this.getHandler(),
+                                ConnectivityManager.TYPE_WIFI);
 
         setupNetworkReceiver();
 
@@ -210,8 +215,6 @@
 
         setInitialState(mWatchdogDisabledState);
         updateSettings();
-        mShowDisabledNotification = getSettingsBoolean(mContentResolver,
-                Settings.Secure.WIFI_WATCHDOG_SHOW_DISABLED_NETWORK_POPUP, true);
     }
 
     public static WifiWatchdogStateMachine makeWifiWatchdogStateMachine(Context context) {
@@ -316,6 +319,9 @@
         mContext.getContentResolver().registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_URL),
                 false, contentObserver);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_SHOW_DISABLED_NETWORK_POPUP)
+                , false, contentObserver);
     }
 
     /**
@@ -354,7 +360,7 @@
     public void dump(PrintWriter pw) {
         pw.print("WatchdogStatus: ");
         pw.print("State " + getCurrentState());
-        pw.println(", network [" + mInitialConnInfo + "]");
+        pw.println(", network [" + mConnectionInfo + "]");
         pw.print("checkFailures   " + mNumCheckFailures);
         pw.println(", bssids: " + mBssids);
         pw.println("lastSingleCheck: " + mOnlineWatchState.lastCheckTime);
@@ -394,6 +400,8 @@
         mWalledGardenIntervalMs = Secure.getLong(mContentResolver,
                 Secure.WIFI_WATCHDOG_WALLED_GARDEN_INTERVAL_MS,
                 DEFAULT_WALLED_GARDEN_INTERVAL_MS);
+        mShowDisabledNotification = getSettingsBoolean(mContentResolver,
+                Settings.Secure.WIFI_WATCHDOG_SHOW_DISABLED_NETWORK_POPUP, true);
     }
 
     /**
@@ -418,17 +426,42 @@
     }
 
     /**
-   *
-   */
+     * Uses {@link #mConnectionInfo}.
+     */
+    private void updateBssids() {
+        String curSsid = mConnectionInfo.getSSID();
+        List<ScanResult> results = mWifiManager.getScanResults();
+        int oldNumBssids = mBssids.size();
+
+        if (results == null) {
+            if (DBG) {
+                Slog.d(WWSM_TAG, "updateBssids: Got null scan results!");
+            }
+            return;
+        }
+
+        for (ScanResult result : results) {
+            if (result == null || result.SSID == null) {
+                if (DBG) {
+                    Slog.d(WWSM_TAG, "Received invalid scan result: " + result);
+                }
+                continue;
+            }
+            if (curSsid.equals(result.SSID))
+                mBssids.add(result.BSSID);
+        }
+    }
+
     private void resetWatchdogState() {
         if (VDBG) {
             Slog.v(WWSM_TAG, "Resetting watchdog state...");
         }
-        mInitialConnInfo = null;
+        mConnectionInfo = null;
         mDisableAPNextFailure = false;
         mLastWalledGardenCheckTime = null;
         mNumCheckFailures = 0;
         mBssids.clear();
+        cancelNetworkNotification();
     }
 
     private void popUpBrowser() {
@@ -439,11 +472,11 @@
         mContext.startActivity(intent);
     }
 
-    private void displayDisabledNetworkNotification() {
+    private void displayDisabledNetworkNotification(String ssid) {
         Resources r = Resources.getSystem();
         CharSequence title =
                 r.getText(com.android.internal.R.string.wifi_watchdog_network_disabled);
-        CharSequence msg =
+        String msg = ssid +
                 r.getText(com.android.internal.R.string.wifi_watchdog_network_disabled_detailed);
 
         Notification wifiDisabledWarning = new Notification.Builder(mContext)
@@ -453,7 +486,7 @@
             .setContentTitle(title)
             .setContentText(msg)
             .setContentIntent(PendingIntent.getActivity(mContext, 0,
-                    new Intent(Settings.ACTION_WIFI_IP_SETTINGS)
+                    new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK)
                         .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0))
             .setWhen(System.currentTimeMillis())
             .setAutoCancel(true)
@@ -462,7 +495,17 @@
         NotificationManager notificationManager = (NotificationManager) mContext
                 .getSystemService(Context.NOTIFICATION_SERVICE);
 
-        notificationManager.notify("WifiWatchdog", wifiDisabledWarning.icon, wifiDisabledWarning);
+        notificationManager.notify(WATCHDOG_NOTIFICATION_ID, 1, wifiDisabledWarning);
+        mNotificationShown = true;
+    }
+
+    public void cancelNetworkNotification() {
+        if (mNotificationShown) {
+            NotificationManager notificationManager = (NotificationManager) mContext
+                    .getSystemService(Context.NOTIFICATION_SERVICE);
+            notificationManager.cancel(WATCHDOG_NOTIFICATION_ID, 1);
+            mNotificationShown = false;
+        }
     }
 
     /**
@@ -535,6 +578,7 @@
 
                     switch (networkInfo.getState()) {
                         case CONNECTED:
+                            cancelNetworkNotification();
                             WifiInfo wifiInfo = (WifiInfo)
                                 stateChangeIntent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
                             if (wifiInfo == null) {
@@ -549,6 +593,8 @@
                             }
 
                             initConnection(wifiInfo);
+                            mConnectionInfo = wifiInfo;
+                            updateBssids();
                             transitionTo(mDnsCheckingState);
                             mNetEventCounter++;
                             return HANDLED;
@@ -577,16 +623,15 @@
          */
         private void initConnection(WifiInfo wifiInfo) {
             if (VDBG) {
-                Slog.v(WWSM_TAG, "Connected:: old " + wifiInfoToStr(mInitialConnInfo) +
+                Slog.v(WWSM_TAG, "Connected:: old " + wifiInfoToStr(mConnectionInfo) +
                         " ==> new " + wifiInfoToStr(wifiInfo));
             }
 
-            if (mInitialConnInfo == null || !wifiInfo.getSSID().equals(mInitialConnInfo.getSSID())) {
+            if (mConnectionInfo == null || !wifiInfo.getSSID().equals(mConnectionInfo.getSSID())) {
                 resetWatchdogState();
-            } else if (!wifiInfo.getBSSID().equals(mInitialConnInfo.getBSSID())) {
+            } else if (!wifiInfo.getBSSID().equals(mConnectionInfo.getBSSID())) {
                 mDisableAPNextFailure = false;
             }
-            mInitialConnInfo = wifiInfo;
         }
 
         @Override
@@ -604,27 +649,7 @@
         public boolean processMessage(Message msg) {
             switch (msg.what) {
                 case EVENT_SCAN_RESULTS_AVAILABLE:
-                    String curSsid = mInitialConnInfo.getSSID();
-                    List<ScanResult> results = mWifiManager.getScanResults();
-                    int oldNumBssids = mBssids.size();
-
-                    if (results == null) {
-                        if (DBG) {
-                            Slog.d(WWSM_TAG, "updateBssids: Got null scan results!");
-                        }
-                        return HANDLED;
-                    }
-
-                    for (ScanResult result : results) {
-                        if (result == null || result.SSID == null) {
-                            if (VDBG) {
-                                Slog.v(WWSM_TAG, "Received invalid scan result: " + result);
-                            }
-                            continue;
-                        }
-                        if (curSsid.equals(result.SSID))
-                            mBssids.add(result.BSSID);
-                    }
+                    updateBssids();
                     return HANDLED;
                 case EVENT_WATCHDOG_SETTINGS_CHANGE:
                     // Stop current checks, but let state update
@@ -633,40 +658,46 @@
             }
             return NOT_HANDLED;
         }
-
     }
 
     class DnsCheckingState extends State {
-        int dnsCheckTries = 0;
         int dnsCheckSuccesses = 0;
+        int dnsCheckTries = 0;
         String dnsCheckLogStr = "";
+        Set<Integer> ids = new HashSet<Integer>();
 
         @Override
         public void enter() {
             dnsCheckSuccesses = 0;
             dnsCheckTries = 0;
+            ids.clear();
+            InetAddress dns = mDnsPinger.getDns();
             if (DBG) {
                 Slog.d(WWSM_TAG, "Starting DNS pings at " + SystemClock.elapsedRealtime());
                 dnsCheckLogStr = String.format("Pinging %s on ssid [%s]: ",
-                        mDnsPinger.getDns(), mInitialConnInfo.getSSID());
+                        mDnsPinger.getDns(), mConnectionInfo.getSSID());
             }
 
-            sendCheckStepMessage(0);
+            for (int i=0; i < mNumDnsPings; i++) {
+                ids.add(mDnsPinger.pingDnsAsync(dns, mDnsPingTimeoutMs,
+                        DNS_INTRATEST_PING_INTERVAL * i));
+            }
         }
 
         @Override
         public boolean processMessage(Message msg) {
-            if (msg.what != MESSAGE_CHECK_STEP) {
+            if (msg.what != DnsPinger.DNS_PING_RESULT) {
                 return NOT_HANDLED;
             }
-            if (msg.arg1 != mNetEventCounter) {
-                Slog.d(WWSM_TAG, "Check step out of sync, ignoring...");
+
+            int pingID = msg.arg1;
+            int pingResponseTime = msg.arg2;
+
+            if (!ids.contains(pingID)) {
+                Slog.w(WWSM_TAG, "Received a Dns response with unknown ID!");
                 return HANDLED;
             }
-
-            long pingResponseTime = mDnsPinger.pingDns(mDnsPinger.getDns(),
-                    mDnsPingTimeoutMs);
-
+            ids.remove(pingID);
             dnsCheckTries++;
             if (pingResponseTime >= 0)
                 dnsCheckSuccesses++;
@@ -730,11 +761,15 @@
                 return HANDLED;
             }
 
-            // Still in dns check step
-            sendCheckStepMessage(DNS_PING_INTERVAL_MS);
             return HANDLED;
         }
 
+        @Override
+        public void exit() {
+            mDnsPinger.cancelPings();
+        }
+
+
         private boolean shouldCheckWalledGarden() {
             if (!mWalledGardenTestEnabled) {
                 if (VDBG)
@@ -752,11 +787,6 @@
             }
             return true;
         }
-
-        private void sendCheckStepMessage(long delay) {
-            sendMessageDelayed(obtainMessage(MESSAGE_CHECK_STEP, mNetEventCounter, 0), delay);
-        }
-
     }
 
     class OnlineWatchState extends State {
@@ -779,12 +809,15 @@
         int checkGuard = 0;
         Long lastCheckTime = null;
 
+        int curPingID = 0;
+
         @Override
         public void enter() {
             lastCheckTime = SystemClock.elapsedRealtime();
             signalUnstable = false;
             checkGuard++;
             unstableSignalChecks = false;
+            curPingID = 0;
             triggerSingleDnsCheck();
         }
 
@@ -820,8 +853,18 @@
                         return HANDLED;
                     }
                     lastCheckTime = SystemClock.elapsedRealtime();
-                    long responseTime = mDnsPinger.pingDns(mDnsPinger.getDns(),
-                            mDnsPingTimeoutMs);
+                    curPingID = mDnsPinger.pingDnsAsync(mDnsPinger.getDns(),
+                            mDnsPingTimeoutMs, 0);
+                    return HANDLED;
+                case DnsPinger.DNS_PING_RESULT:
+                    if ((short) msg.arg1 != curPingID) {
+                        if (VDBG) {
+                            Slog.v(WWSM_TAG, "Received non-matching DnsPing w/ id: " +
+                                    msg.arg1);
+                        }
+                        return HANDLED;
+                    }
+                    int responseTime = msg.arg2;
                     if (responseTime >= 0) {
                         if (VDBG) {
                             Slog.v(WWSM_TAG, "Ran a single DNS ping. Response time: "
@@ -842,6 +885,11 @@
             return NOT_HANDLED;
         }
 
+        @Override
+        public void exit() {
+            mDnsPinger.cancelPings();
+        }
+
         /**
          * Times a dns check with an interval based on {@link #signalUnstable}
          */
@@ -879,7 +927,8 @@
                 return HANDLED;
             }
 
-            if (mDisableAPNextFailure || mNumCheckFailures >= mMaxSsidBlacklists) {
+            if (mDisableAPNextFailure || mNumCheckFailures >= mBssids.size()
+                    || mNumCheckFailures >= mMaxSsidBlacklists) {
                 if (hasNoMobileData()) {
                     Slog.w(WWSM_TAG, "Would disable bad network, but device has no mobile data!" +
                             "  Going idle...");
@@ -887,23 +936,26 @@
                     transitionTo(mNotConnectedState);
                     return HANDLED;
                 }
+
                 // TODO : Unban networks if they had low signal ?
-                Slog.i(WWSM_TAG, "Disabling current SSID " + wifiInfoToStr(mInitialConnInfo)
+                Slog.i(WWSM_TAG, "Disabling current SSID " + wifiInfoToStr(mConnectionInfo)
                         + ".  " + "numCheckFailures " + mNumCheckFailures
                         + ", numAPs " + mBssids.size());
-                mWifiManager.disableNetwork(mInitialConnInfo.getNetworkId());
-                if (mShowDisabledNotification) {
-                    displayDisabledNetworkNotification();
-                    mShowDisabledNotification = false;
-                    putSettingsBoolean(mContentResolver,
-                            Settings.Secure.WIFI_WATCHDOG_SHOW_DISABLED_NETWORK_POPUP, false);
+                int networkId = mConnectionInfo.getNetworkId();
+                if (!mHasConnectedWifiManager) {
+                    mWifiManager.asyncConnect(mContext, getHandler());
+                    mHasConnectedWifiManager = true;
+                }
+                mWifiManager.disableNetwork(networkId, WifiConfiguration.DISABLED_DNS_FAILURE);
+                if (mShowDisabledNotification && mConnectionInfo.isExplicitConnect()) {
+                    displayDisabledNetworkNotification(mConnectionInfo.getSSID());
                 }
                 transitionTo(mNotConnectedState);
             } else {
-                Slog.i(WWSM_TAG, "Blacklisting current BSSID.  " + wifiInfoToStr(mInitialConnInfo)
+                Slog.i(WWSM_TAG, "Blacklisting current BSSID.  " + wifiInfoToStr(mConnectionInfo)
                        + "numCheckFailures " + mNumCheckFailures + ", numAPs " + mBssids.size());
 
-                mWifiManager.addToBlacklist(mInitialConnInfo.getBSSID());
+                mWifiManager.addToBlacklist(mConnectionInfo.getBSSID());
                 mWifiManager.reassociate();
                 transitionTo(mBlacklistedApState);
             }
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 4988f0b..28afd44 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.server;
+package android.net.wifi.p2p;
 
 import android.app.AlertDialog;
 import android.content.BroadcastReceiver;
@@ -31,20 +31,13 @@
 import android.net.wifi.WifiStateMachine;
 import android.net.wifi.WpsConfiguration;
 import android.net.wifi.WpsConfiguration.Setup;
-import android.net.wifi.p2p.IWifiP2pManager;
-import android.net.wifi.p2p.WifiP2pConfig;
-import android.net.wifi.p2p.WifiP2pDevice;
 import android.net.wifi.p2p.WifiP2pDevice.Status;
-import android.net.wifi.p2p.WifiP2pDeviceList;
-import android.net.wifi.p2p.WifiP2pGroup;
-import android.net.wifi.p2p.WifiP2pManager;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Handler;
-import android.os.Messenger;
 import android.os.HandlerThread;
-import android.os.IBinder;
 import android.os.Message;
+import android.os.Messenger;
 import android.util.Slog;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -55,9 +48,9 @@
 import java.io.PrintWriter;
 import java.util.Collection;
 
+import com.android.internal.R;
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
-import com.android.internal.R;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;