Merge "Fix AnimatorSet cancellation issues"
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 876d555..bdc695f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -84,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";
@@ -1499,6 +1498,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
@@ -1513,6 +1518,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
@@ -1578,6 +1617,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
@@ -1642,6 +1705,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
@@ -8454,6 +8626,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();
   }
@@ -11116,6 +11289,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);
@@ -11130,7 +11304,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";
@@ -11275,6 +11449,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;
   }
@@ -22068,45 +22252,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 {
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/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b6c64cb..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();
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/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/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/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/BluetoothAdapterStateMachine.java b/core/java/android/server/BluetoothAdapterStateMachine.java
index cb18ade..031375ec 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..3029c9d 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -1565,6 +1565,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)) {
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/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/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/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/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..d977029 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);
     }
 
@@ -519,14 +520,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 +546,7 @@
         }
     }
 
+    /** @noinspection UnusedParameters*/
     private int getDefaultMargin(View c, boolean horizontal, boolean leading) {
         if (c.getClass() == Space.class) {
             return 0;
@@ -576,7 +570,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 +578,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,15 +740,6 @@
         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);
-    }
-
     @Override
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
@@ -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);
+                canvas.drawRect(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);
+                canvas.drawRect(
+                        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/TextView.java b/core/java/android/widget/TextView.java
index 65ee745..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);
     }
@@ -2081,7 +2084,7 @@
                                        TextAppearance_textStyle, -1);
 
         setTypefaceByIndex(typefaceIndex, styleIndex);
-        
+
         if (appearance.getBoolean(com.android.internal.R.styleable.TextAppearance_textAllCaps,
                 false)) {
             setTransformationMethod(new AllCapsTransformationMethod(getContext()));
@@ -3019,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
@@ -8446,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 =
@@ -8757,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);
@@ -8795,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(
@@ -8803,11 +9032,9 @@
                 }
 
                 childView.setTag(new SuggestionInfo());
-                mSuggestionsContainer.addView(childView);
+                mContentView.addView(childView);
                 childView.setOnClickListener(this);
             }
-
-            mPopupWindow.setContentView(mSuggestionsContainer);
         }
 
         private class SuggestionInfo {
@@ -8827,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;
@@ -8869,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();
@@ -8889,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;
@@ -8900,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) {
@@ -9071,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) {
@@ -9141,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() {
@@ -9359,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);
 
@@ -9452,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);
@@ -9482,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
@@ -9524,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) {
@@ -9573,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
@@ -9581,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;
 
@@ -9615,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
@@ -9641,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();
@@ -9665,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();
         }
 
@@ -9699,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) {
@@ -9734,7 +9881,7 @@
             return mContainer.isShowing();
         }
 
-        private boolean isPositionVisible() {
+        private boolean isVisible() {
             // Always show a dragging handle.
             if (mIsDragging) {
                 return true;
@@ -9744,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
@@ -9857,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;
                 }
@@ -9963,7 +10077,7 @@
                         mTextSelectHandleRes);
             }
             mDrawable = mSelectHandleCenter;
-            mHotspotX = mDrawable.getIntrinsicWidth() / 2.0f;
+            mHotspotX = mDrawable.getIntrinsicWidth() / 2;
         }
 
         @Override
@@ -9977,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();
@@ -10008,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
@@ -10038,7 +10154,7 @@
                         mTextSelectHandleLeftRes);
             }
             mDrawable = mSelectHandleLeft;
-            mHotspotX = mDrawable.getIntrinsicWidth() * 3.0f / 4.0f;
+            mHotspotX = (mDrawable.getIntrinsicWidth() * 3) / 4;
         }
 
         @Override
@@ -10047,7 +10163,7 @@
         }
 
         @Override
-        public void updateOffset(int offset) {
+        public void updateSelection(int offset) {
             Selection.setSelection((Spannable) mText, offset, getSelectionEnd());
         }
 
@@ -10063,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() {
@@ -10079,7 +10195,7 @@
                         mTextSelectHandleRightRes);
             }
             mDrawable = mSelectHandleRight;
-            mHotspotX = mDrawable.getIntrinsicWidth() / 4.0f;
+            mHotspotX = mDrawable.getIntrinsicWidth() / 4;
         }
 
         @Override
@@ -10088,7 +10204,7 @@
         }
 
         @Override
-        public void updateOffset(int offset) {
+        public void updateSelection(int offset) {
             Selection.setSelection((Spannable) mText, getSelectionStart(), offset);
         }
 
@@ -10104,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..266728b9 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/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/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/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 21c3f1e..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,16 +292,6 @@
         android:description="@string/permdesc_setAlarm"
         android:protectionLevel="normal" />
 
-   <!-- Allows an application to read/write the voicemails owned by its own
-        package. -->
-   <!--  TODO: delete this permission when dependent content provider &
-        application code has been migrated to use ADD_VOICEMAIL instead -->
-    <permission android:name="com.android.voicemail.permission.READ_WRITE_OWN_VOICEMAIL"
-        android:permissionGroup="android.permission-group.PERSONAL_INFO"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_readWriteOwnVoicemail"
-        android:description="@string/permdesc_readWriteOwnVoicemail" />
-
    <!-- 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"
@@ -402,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-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-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/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/layout/keyguard_screen_password_landscape.xml b/core/res/res/layout/keyguard_screen_password_landscape.xml
index 960907d..c2536b7 100644
--- a/core/res/res/layout/keyguard_screen_password_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_password_landscape.xml
@@ -118,41 +118,36 @@
     />
 
     <!-- Column 1 -->
-    <Space android:layout_width="32dip" android:layout_rowSpan="7" />
+    <Space android:layout_width="16dip" android:layout_rowSpan="7" />
 
     <!-- Column 2 - password entry field and PIN keyboard -->
-    <LinearLayout
-        android:orientation="vertical"
-        android:layout_gravity="center|fill"
-        android:layout_rowSpan="7">
-
-        <EditText android:id="@+id/passwordEntry"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            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"
-            />
-
-        <!-- 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"
+    <EditText android:id="@+id/passwordEntry"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:layout_gravity="fill"
+        android:gravity="center"
+        android:singleLine="true"
+        android:textStyle="normal"
+        android:inputType="textPassword"
+        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|actionDone"
         />
 
-    </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="6"
+    />
 
     <!-- Music transport control -->
     <include android:id="@+id/transport"
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/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/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 2dfe453..f85dd85 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1803,6 +1803,183 @@
   <public type="style" name="Widget.Holo.Light.ActionBar.TabText.Inverse" />
   <public type="style" name="Widget.Holo.Light.ActionMode.Inverse" />
 
+  <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 a6c92f2..6a3c2d5 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -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,14 +2151,6 @@
 
     <!-- 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>
-    <!-- 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>
-
-    <!-- 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_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] -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 5aa47b7..21f1cef 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
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 2b1b693..615a37d 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.
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 02531222..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/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/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/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/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/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 7258e11..e7a306b 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,110 @@
     }
 
     /**
+     * @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
+     * 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;
+    }
+
+    /**
+     * @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
+     */
+    public void notifyRemoteControlInformationChanged(ComponentName eventReceiver) {
+        IAudioService service = getService();
+        try {
+            service.notifyRemoteControlInformationChanged(eventReceiver);
+        } 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..bf1585d 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,100 @@
         }
     }
 
-    private static class RemoteControlStackEntry {
-        public ComponentName mReceiverComponent;// always non null
-        // TODO implement registration expiration?
-        //public int mRegistrationTime;
+    private final static 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 static SoftReference<IRemoteControlClient> mCurrentRcClientRef =
+            new SoftReference<IRemoteControlClient>(null);
 
-        public RemoteControlStackEntry() {
-        }
+    /**
+     * A monotonically increasing generation counter for mCurrentRcClientRef.
+     * Only accessed with a lock on mCurrentRcLock.
+     */
+    private static int mCurrentRcClientGen = 0;
 
-        public RemoteControlStackEntry(ComponentName r) {
-            mReceiverComponent = r;
+    /**
+     * 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 static IRemoteControlClient getRemoteControlClient(int rcClientId) {
+        synchronized(mCurrentRcLock) {
+            if (rcClientId == mCurrentRcClientGen) {
+                return mCurrentRcClientRef.get();
+            } else {
+                return null;
+            }
         }
     }
 
+    /**
+     * 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 +2950,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 +3006,7 @@
             ComponentName receiverComponentName = ComponentName.unflattenFromString(receiverName);
             registerMediaButtonEventReceiver(receiverComponentName);
         }
+        // upon restoring (e.g. after boot), do we want to refresh all remotes?
     }
 
     /**
@@ -2921,14 +3019,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 +3054,88 @@
         }
     }
 
+    /**
+     * 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();
+        }
+        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) {
+            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 +3143,74 @@
     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) */
+    public void notifyRemoteControlInformationChanged(ComponentName eventReceiver) {
+        synchronized(mAudioFocusLock) {
+            synchronized(mRCStack) {
+                // only refresh if the eventReceiver is at the top of the stack
+                if (isCurrentRcController(eventReceiver)) {
+                    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..9afe553 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,11 @@
 
     void unregisterMediaButtonEventReceiver(in ComponentName eventReceiver);
 
+    void registerRemoteControlClient(in ComponentName eventReceiver,
+           in IRemoteControlClient rcClient, in String callingPackageName);
+
+    void notifyRemoteControlInformationChanged(in ComponentName eventReceiver);
+
     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/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 a8fadf2c..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/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/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml b/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml
index 3668b8c..7dfa53e 100644
--- a/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml
+++ b/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml
@@ -18,10 +18,20 @@
  */
 -->
 
-<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"
+              android:padding="16dp" >
+
+    <ScrollView 
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:layout_width="match_parent">
+        <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,13 +73,21 @@
               android:layout_marginLeft="30dp"
               android:layout_below="@id/enc_password"
               android:layout_marginBottom="30dp" />
+        </LinearLayout>
+    </ScrollView>
+
+    <LinearLayout android:orientation="horizontal"
+                  android:layout_height="wrap_content"
+                  android:layout_width="match_parent"
+                  android:layout_gravity="bottom">
 
     <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" />
+            android:layout_width="0dp"
+            android:layout_weight="1" />
 
     <Button android:id="@+id/button_deny"
             android:text="@string/deny_backup_button_label"
@@ -77,6 +95,9 @@
             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>
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml b/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml
index 38fcc496..4927cbb 100644
--- a/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml
+++ b/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml
@@ -18,65 +18,86 @@
  */
 -->
 
-<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>
+    <LinearLayout android:orientation="horizontal"
+                  android:layout_height="wrap_content"
+                  android:layout_width="match_parent"
+                  android:layout_gravity="bottom">
+
+        <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="0dp"
+                android:layout_weight="1" />
+
+        <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="0dp"
+                android:layout_weight="1" />
+
+    </LinearLayout>
+
+</LinearLayout>
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/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/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/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/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index d25a827..25eab26 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -505,7 +505,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);
     }
@@ -1872,7 +1873,7 @@
     }
 
     void updateExpandedSize() {
-        if (mExpandedDialog != null) {
+        if (mExpandedDialog != null && mExpandedParams != null) {
             mExpandedParams.width = mDisplaySize.x;
             mExpandedParams.height = getExpandedHeight(mDisplaySize.y);
             if (!mExpandedVisible) {
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..97b6298 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);
             }
@@ -682,10 +683,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()) {
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..c7b6f20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -1606,6 +1606,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();
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/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 9c19da2..14f7c11 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -552,6 +552,8 @@
             if (!st.shownPanelView.hasFocus()) {
                 st.shownPanelView.requestFocus();
             }
+        } else if (!st.isInExpandedMode) {
+            width = MATCH_PARENT;
         }
 
         st.isOpen = true;
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 ec45530..2355d5c 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,
@@ -4143,7 +4305,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;
 
@@ -4363,6 +4529,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;
         }
@@ -4490,6 +4663,12 @@
     return result;
 }
 
+AudioFlinger::RecordThread::RecordTrack* AudioFlinger::RecordThread::track()
+{
+    Mutex::Autolock _l(mLock);
+    return mTrack;
+}
+
 // ----------------------------------------------------------------------------
 
 int AudioFlinger::openOutput(uint32_t *pDevices,
@@ -4874,10 +5053,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,
@@ -4915,14 +5090,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
@@ -5003,6 +5170,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));
 
@@ -5069,10 +5243,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);
@@ -5091,24 +5265,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;
     }
 
@@ -5143,7 +5317,7 @@
             AudioSystem::registerEffect(&effect->desc(),
                                         dstOutput,
                                         strategy,
-                                        session,
+                                        sessionId,
                                         effect->id());
         }
         effect = chain->getEffectFromId_l(0);
@@ -5385,6 +5559,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
@@ -5451,6 +5626,7 @@
         if (mEffectChains[i]->sessionId() < session) break;
     }
     mEffectChains.insertAt(chain, i);
+    checkSuspendOnAddEffectChain_l(chain);
 
     return NO_ERROR;
 }
@@ -5463,6 +5639,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) {
@@ -5540,6 +5717,8 @@
     chain->setInBuffer(NULL);
     chain->setOutBuffer(NULL);
 
+    checkSuspendOnAddEffectChain_l(chain);
+
     mEffectChains.add(chain);
 
     return NO_ERROR;
@@ -5552,6 +5731,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;
@@ -5570,7 +5750,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;
@@ -5634,14 +5814,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;
 }
@@ -5657,13 +5840,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*/);
         }
     }
 
@@ -5677,8 +5868,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);
@@ -6139,6 +6343,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;
@@ -6235,7 +6450,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);
 
@@ -6258,30 +6474,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) {
@@ -6373,11 +6625,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);
     }
@@ -6448,7 +6702,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;
@@ -6463,7 +6717,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;
@@ -6479,6 +6733,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()
 {
@@ -6773,6 +7043,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 7b6215f..791341a 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 ---
@@ -848,7 +884,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);
@@ -908,6 +944,7 @@
                     bool        setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
 
                     void        dump(char* buffer, size_t size);
+
         private:
             friend class AudioFlinger;
             friend class RecordThread;
@@ -950,8 +987,6 @@
                 AudioStreamIn* getInput() { return mInput; }
                 virtual audio_stream_t* stream() { return &mInput->stream->common; }
 
-
-                void        setTrack(RecordTrack *recordTrack) { mTrack = recordTrack; }
         virtual status_t    getNextBuffer(AudioBufferProvider::Buffer* buffer);
         virtual void        releaseBuffer(AudioBufferProvider::Buffer* buffer);
         virtual bool        checkForNewParameters_l();
@@ -963,6 +998,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();
@@ -1059,6 +1095,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);
@@ -1071,6 +1108,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);
 
@@ -1099,6 +1140,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
@@ -1131,13 +1173,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(); }
@@ -1160,6 +1206,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.
@@ -1174,6 +1222,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() {
@@ -1191,6 +1243,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);
@@ -1221,6 +1274,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:
@@ -1228,6 +1290,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
@@ -1243,6 +1320,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 {
@@ -1283,7 +1364,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/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 1bbe934..bf9e014 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;
@@ -737,6 +738,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();
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/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/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index ecbad099..b69cc31c1d 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();
 
@@ -198,6 +191,7 @@
             if (config.routes != null) {
                 jniSetRoutes(interfaze, config.routes);
             }
+            // TODO: bind the service
             if (mInterface != null && !mInterface.equals(interfaze)) {
                 jniReset(mInterface);
             }
@@ -211,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);
@@ -235,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);
@@ -263,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)
@@ -274,7 +275,6 @@
                     .setOngoing(true)
                     .getNotification();
             nm.notify(R.drawable.vpn_connected, notification);
-            Binder.restoreCallingIdentity(identity);
         }
     }
 
@@ -283,9 +283,7 @@
                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
 
         if (nm != null) {
-            long identity = Binder.clearCallingIdentity();
             nm.cancel(R.drawable.vpn_connected);
-            Binder.restoreCallingIdentity(identity);
         }
     }
 
@@ -355,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 3d977d0..36371a57 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -5025,16 +5025,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/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/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/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/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index de49eb4..331d5c0 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;
@@ -69,7 +70,6 @@
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.WorkSource;
-import android.server.WifiP2pService;
 import android.provider.Settings;
 import android.util.EventLog;
 import android.util.Log;
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index be9dfcf..168c68b 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
@@ -82,7 +84,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 +93,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 +116,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
      */
@@ -189,8 +190,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();
 
@@ -637,36 +639,43 @@
     }
 
     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());
+                        dns, mInitialConnInfo.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 +739,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 +765,6 @@
             }
             return true;
         }
-
-        private void sendCheckStepMessage(long delay) {
-            sendMessageDelayed(obtainMessage(MESSAGE_CHECK_STEP, mNetEventCounter, 0), delay);
-        }
-
     }
 
     class OnlineWatchState extends State {
@@ -779,12 +787,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 +831,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 +863,11 @@
             return NOT_HANDLED;
         }
 
+        @Override
+        public void exit() {
+            mDnsPinger.cancelPings();
+        }
+
         /**
          * Times a dns check with an interval based on {@link #signalUnstable}
          */
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;