Merge "Exposing the API to support widgets in Recents."
diff --git a/api/current.txt b/api/current.txt
index 8ff2253..3669ca2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -267,6 +267,7 @@
     field public static final int actionModeSplitBackground = 16843677; // 0x101039d
     field public static final int actionModeStyle = 16843668; // 0x1010394
     field public static final int actionOverflowButtonStyle = 16843510; // 0x10102f6
+    field public static final int actionOverflowMenuStyle = 16843857; // 0x1010451
     field public static final int actionProviderClass = 16843657; // 0x1010389
     field public static final int actionViewClass = 16843516; // 0x10102fc
     field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
@@ -1858,28 +1859,28 @@
     field public static final int TextAppearance_Medium = 16973892; // 0x1030044
     field public static final int TextAppearance_Medium_Inverse = 16973893; // 0x1030045
     field public static final int TextAppearance_Quantum = 16974352; // 0x1030210
-    field public static final int TextAppearance_Quantum_Body1 = 16974542; // 0x10302ce
-    field public static final int TextAppearance_Quantum_Body2 = 16974541; // 0x10302cd
-    field public static final int TextAppearance_Quantum_Button = 16974545; // 0x10302d1
-    field public static final int TextAppearance_Quantum_Caption = 16974543; // 0x10302cf
+    field public static final int TextAppearance_Quantum_Body1 = 16974544; // 0x10302d0
+    field public static final int TextAppearance_Quantum_Body2 = 16974543; // 0x10302cf
+    field public static final int TextAppearance_Quantum_Button = 16974547; // 0x10302d3
+    field public static final int TextAppearance_Quantum_Caption = 16974545; // 0x10302d1
     field public static final int TextAppearance_Quantum_DialogWindowTitle = 16974353; // 0x1030211
-    field public static final int TextAppearance_Quantum_Display1 = 16974537; // 0x10302c9
-    field public static final int TextAppearance_Quantum_Display2 = 16974536; // 0x10302c8
-    field public static final int TextAppearance_Quantum_Display3 = 16974535; // 0x10302c7
-    field public static final int TextAppearance_Quantum_Display4 = 16974534; // 0x10302c6
-    field public static final int TextAppearance_Quantum_Headline = 16974538; // 0x10302ca
+    field public static final int TextAppearance_Quantum_Display1 = 16974539; // 0x10302cb
+    field public static final int TextAppearance_Quantum_Display2 = 16974538; // 0x10302ca
+    field public static final int TextAppearance_Quantum_Display3 = 16974537; // 0x10302c9
+    field public static final int TextAppearance_Quantum_Display4 = 16974536; // 0x10302c8
+    field public static final int TextAppearance_Quantum_Headline = 16974540; // 0x10302cc
     field public static final int TextAppearance_Quantum_Inverse = 16974354; // 0x1030212
     field public static final int TextAppearance_Quantum_Large = 16974355; // 0x1030213
     field public static final int TextAppearance_Quantum_Large_Inverse = 16974356; // 0x1030214
     field public static final int TextAppearance_Quantum_Medium = 16974357; // 0x1030215
     field public static final int TextAppearance_Quantum_Medium_Inverse = 16974358; // 0x1030216
-    field public static final int TextAppearance_Quantum_Menu = 16974544; // 0x10302d0
+    field public static final int TextAppearance_Quantum_Menu = 16974546; // 0x10302d2
     field public static final int TextAppearance_Quantum_SearchResult_Subtitle = 16974359; // 0x1030217
     field public static final int TextAppearance_Quantum_SearchResult_Title = 16974360; // 0x1030218
     field public static final int TextAppearance_Quantum_Small = 16974361; // 0x1030219
     field public static final int TextAppearance_Quantum_Small_Inverse = 16974362; // 0x103021a
-    field public static final int TextAppearance_Quantum_Subhead = 16974540; // 0x10302cc
-    field public static final int TextAppearance_Quantum_Title = 16974539; // 0x10302cb
+    field public static final int TextAppearance_Quantum_Subhead = 16974542; // 0x10302ce
+    field public static final int TextAppearance_Quantum_Title = 16974541; // 0x10302cd
     field public static final int TextAppearance_Quantum_Widget = 16974364; // 0x103021c
     field public static final int TextAppearance_Quantum_Widget_ActionBar_Menu = 16974365; // 0x103021d
     field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle = 16974366; // 0x103021e
@@ -2351,92 +2352,94 @@
     field public static final int Widget_Quantum_GridView = 16974445; // 0x103026d
     field public static final int Widget_Quantum_HorizontalScrollView = 16974446; // 0x103026e
     field public static final int Widget_Quantum_ImageButton = 16974447; // 0x103026f
-    field public static final int Widget_Quantum_Light = 16974473; // 0x1030289
-    field public static final int Widget_Quantum_Light_ActionBar = 16974474; // 0x103028a
-    field public static final int Widget_Quantum_Light_ActionBar_Solid = 16974475; // 0x103028b
-    field public static final int Widget_Quantum_Light_ActionBar_TabBar = 16974476; // 0x103028c
-    field public static final int Widget_Quantum_Light_ActionBar_TabText = 16974477; // 0x103028d
-    field public static final int Widget_Quantum_Light_ActionBar_TabView = 16974478; // 0x103028e
-    field public static final int Widget_Quantum_Light_ActionButton = 16974479; // 0x103028f
-    field public static final int Widget_Quantum_Light_ActionButton_CloseMode = 16974480; // 0x1030290
-    field public static final int Widget_Quantum_Light_ActionButton_Overflow = 16974481; // 0x1030291
-    field public static final int Widget_Quantum_Light_ActionMode = 16974482; // 0x1030292
-    field public static final int Widget_Quantum_Light_AutoCompleteTextView = 16974483; // 0x1030293
-    field public static final int Widget_Quantum_Light_Button = 16974484; // 0x1030294
-    field public static final int Widget_Quantum_Light_ButtonBar = 16974490; // 0x103029a
-    field public static final int Widget_Quantum_Light_ButtonBar_AlertDialog = 16974491; // 0x103029b
-    field public static final int Widget_Quantum_Light_Button_Borderless = 16974485; // 0x1030295
-    field public static final int Widget_Quantum_Light_Button_Borderless_Small = 16974486; // 0x1030296
-    field public static final int Widget_Quantum_Light_Button_Inset = 16974487; // 0x1030297
-    field public static final int Widget_Quantum_Light_Button_Small = 16974488; // 0x1030298
-    field public static final int Widget_Quantum_Light_Button_Toggle = 16974489; // 0x1030299
-    field public static final int Widget_Quantum_Light_CalendarView = 16974492; // 0x103029c
-    field public static final int Widget_Quantum_Light_CheckedTextView = 16974493; // 0x103029d
-    field public static final int Widget_Quantum_Light_CompoundButton_CheckBox = 16974494; // 0x103029e
-    field public static final int Widget_Quantum_Light_CompoundButton_RadioButton = 16974495; // 0x103029f
-    field public static final int Widget_Quantum_Light_CompoundButton_Star = 16974496; // 0x10302a0
-    field public static final int Widget_Quantum_Light_DropDownItem = 16974497; // 0x10302a1
-    field public static final int Widget_Quantum_Light_DropDownItem_Spinner = 16974498; // 0x10302a2
-    field public static final int Widget_Quantum_Light_EditText = 16974499; // 0x10302a3
-    field public static final int Widget_Quantum_Light_ExpandableListView = 16974500; // 0x10302a4
-    field public static final int Widget_Quantum_Light_FastScroll = 16974501; // 0x10302a5
-    field public static final int Widget_Quantum_Light_FragmentBreadCrumbs = 16974502; // 0x10302a6
-    field public static final int Widget_Quantum_Light_GridView = 16974503; // 0x10302a7
-    field public static final int Widget_Quantum_Light_HorizontalScrollView = 16974504; // 0x10302a8
-    field public static final int Widget_Quantum_Light_ImageButton = 16974505; // 0x10302a9
-    field public static final int Widget_Quantum_Light_ListPopupWindow = 16974506; // 0x10302aa
-    field public static final int Widget_Quantum_Light_ListView = 16974507; // 0x10302ab
-    field public static final int Widget_Quantum_Light_ListView_DropDown = 16974508; // 0x10302ac
-    field public static final int Widget_Quantum_Light_MediaRouteButton = 16974509; // 0x10302ad
-    field public static final int Widget_Quantum_Light_PopupMenu = 16974510; // 0x10302ae
-    field public static final int Widget_Quantum_Light_PopupWindow = 16974511; // 0x10302af
-    field public static final int Widget_Quantum_Light_ProgressBar = 16974512; // 0x10302b0
-    field public static final int Widget_Quantum_Light_ProgressBar_Horizontal = 16974513; // 0x10302b1
-    field public static final int Widget_Quantum_Light_ProgressBar_Inverse = 16974514; // 0x10302b2
-    field public static final int Widget_Quantum_Light_ProgressBar_Large = 16974515; // 0x10302b3
-    field public static final int Widget_Quantum_Light_ProgressBar_Large_Inverse = 16974516; // 0x10302b4
-    field public static final int Widget_Quantum_Light_ProgressBar_Small = 16974517; // 0x10302b5
-    field public static final int Widget_Quantum_Light_ProgressBar_Small_Inverse = 16974518; // 0x10302b6
-    field public static final int Widget_Quantum_Light_ProgressBar_Small_Title = 16974519; // 0x10302b7
-    field public static final int Widget_Quantum_Light_RatingBar = 16974520; // 0x10302b8
-    field public static final int Widget_Quantum_Light_RatingBar_Indicator = 16974521; // 0x10302b9
-    field public static final int Widget_Quantum_Light_RatingBar_Small = 16974522; // 0x10302ba
-    field public static final int Widget_Quantum_Light_ScrollView = 16974523; // 0x10302bb
-    field public static final int Widget_Quantum_Light_SeekBar = 16974524; // 0x10302bc
-    field public static final int Widget_Quantum_Light_SegmentedButton = 16974525; // 0x10302bd
-    field public static final int Widget_Quantum_Light_Spinner = 16974527; // 0x10302bf
-    field public static final int Widget_Quantum_Light_StackView = 16974526; // 0x10302be
-    field public static final int Widget_Quantum_Light_Tab = 16974528; // 0x10302c0
-    field public static final int Widget_Quantum_Light_TabWidget = 16974529; // 0x10302c1
-    field public static final int Widget_Quantum_Light_TextView = 16974530; // 0x10302c2
-    field public static final int Widget_Quantum_Light_TextView_SpinnerItem = 16974531; // 0x10302c3
-    field public static final int Widget_Quantum_Light_WebTextView = 16974532; // 0x10302c4
-    field public static final int Widget_Quantum_Light_WebView = 16974533; // 0x10302c5
+    field public static final int Widget_Quantum_Light = 16974474; // 0x103028a
+    field public static final int Widget_Quantum_Light_ActionBar = 16974475; // 0x103028b
+    field public static final int Widget_Quantum_Light_ActionBar_Solid = 16974476; // 0x103028c
+    field public static final int Widget_Quantum_Light_ActionBar_TabBar = 16974477; // 0x103028d
+    field public static final int Widget_Quantum_Light_ActionBar_TabText = 16974478; // 0x103028e
+    field public static final int Widget_Quantum_Light_ActionBar_TabView = 16974479; // 0x103028f
+    field public static final int Widget_Quantum_Light_ActionButton = 16974480; // 0x1030290
+    field public static final int Widget_Quantum_Light_ActionButton_CloseMode = 16974481; // 0x1030291
+    field public static final int Widget_Quantum_Light_ActionButton_Overflow = 16974482; // 0x1030292
+    field public static final int Widget_Quantum_Light_ActionMode = 16974483; // 0x1030293
+    field public static final int Widget_Quantum_Light_AutoCompleteTextView = 16974484; // 0x1030294
+    field public static final int Widget_Quantum_Light_Button = 16974485; // 0x1030295
+    field public static final int Widget_Quantum_Light_ButtonBar = 16974491; // 0x103029b
+    field public static final int Widget_Quantum_Light_ButtonBar_AlertDialog = 16974492; // 0x103029c
+    field public static final int Widget_Quantum_Light_Button_Borderless = 16974486; // 0x1030296
+    field public static final int Widget_Quantum_Light_Button_Borderless_Small = 16974487; // 0x1030297
+    field public static final int Widget_Quantum_Light_Button_Inset = 16974488; // 0x1030298
+    field public static final int Widget_Quantum_Light_Button_Small = 16974489; // 0x1030299
+    field public static final int Widget_Quantum_Light_Button_Toggle = 16974490; // 0x103029a
+    field public static final int Widget_Quantum_Light_CalendarView = 16974493; // 0x103029d
+    field public static final int Widget_Quantum_Light_CheckedTextView = 16974494; // 0x103029e
+    field public static final int Widget_Quantum_Light_CompoundButton_CheckBox = 16974495; // 0x103029f
+    field public static final int Widget_Quantum_Light_CompoundButton_RadioButton = 16974496; // 0x10302a0
+    field public static final int Widget_Quantum_Light_CompoundButton_Star = 16974497; // 0x10302a1
+    field public static final int Widget_Quantum_Light_DropDownItem = 16974498; // 0x10302a2
+    field public static final int Widget_Quantum_Light_DropDownItem_Spinner = 16974499; // 0x10302a3
+    field public static final int Widget_Quantum_Light_EditText = 16974500; // 0x10302a4
+    field public static final int Widget_Quantum_Light_ExpandableListView = 16974501; // 0x10302a5
+    field public static final int Widget_Quantum_Light_FastScroll = 16974502; // 0x10302a6
+    field public static final int Widget_Quantum_Light_FragmentBreadCrumbs = 16974503; // 0x10302a7
+    field public static final int Widget_Quantum_Light_GridView = 16974504; // 0x10302a8
+    field public static final int Widget_Quantum_Light_HorizontalScrollView = 16974505; // 0x10302a9
+    field public static final int Widget_Quantum_Light_ImageButton = 16974506; // 0x10302aa
+    field public static final int Widget_Quantum_Light_ListPopupWindow = 16974507; // 0x10302ab
+    field public static final int Widget_Quantum_Light_ListView = 16974508; // 0x10302ac
+    field public static final int Widget_Quantum_Light_ListView_DropDown = 16974509; // 0x10302ad
+    field public static final int Widget_Quantum_Light_MediaRouteButton = 16974510; // 0x10302ae
+    field public static final int Widget_Quantum_Light_PopupMenu = 16974511; // 0x10302af
+    field public static final int Widget_Quantum_Light_PopupMenu_Overflow = 16974512; // 0x10302b0
+    field public static final int Widget_Quantum_Light_PopupWindow = 16974513; // 0x10302b1
+    field public static final int Widget_Quantum_Light_ProgressBar = 16974514; // 0x10302b2
+    field public static final int Widget_Quantum_Light_ProgressBar_Horizontal = 16974515; // 0x10302b3
+    field public static final int Widget_Quantum_Light_ProgressBar_Inverse = 16974516; // 0x10302b4
+    field public static final int Widget_Quantum_Light_ProgressBar_Large = 16974517; // 0x10302b5
+    field public static final int Widget_Quantum_Light_ProgressBar_Large_Inverse = 16974518; // 0x10302b6
+    field public static final int Widget_Quantum_Light_ProgressBar_Small = 16974519; // 0x10302b7
+    field public static final int Widget_Quantum_Light_ProgressBar_Small_Inverse = 16974520; // 0x10302b8
+    field public static final int Widget_Quantum_Light_ProgressBar_Small_Title = 16974521; // 0x10302b9
+    field public static final int Widget_Quantum_Light_RatingBar = 16974522; // 0x10302ba
+    field public static final int Widget_Quantum_Light_RatingBar_Indicator = 16974523; // 0x10302bb
+    field public static final int Widget_Quantum_Light_RatingBar_Small = 16974524; // 0x10302bc
+    field public static final int Widget_Quantum_Light_ScrollView = 16974525; // 0x10302bd
+    field public static final int Widget_Quantum_Light_SeekBar = 16974526; // 0x10302be
+    field public static final int Widget_Quantum_Light_SegmentedButton = 16974527; // 0x10302bf
+    field public static final int Widget_Quantum_Light_Spinner = 16974529; // 0x10302c1
+    field public static final int Widget_Quantum_Light_StackView = 16974528; // 0x10302c0
+    field public static final int Widget_Quantum_Light_Tab = 16974530; // 0x10302c2
+    field public static final int Widget_Quantum_Light_TabWidget = 16974531; // 0x10302c3
+    field public static final int Widget_Quantum_Light_TextView = 16974532; // 0x10302c4
+    field public static final int Widget_Quantum_Light_TextView_SpinnerItem = 16974533; // 0x10302c5
+    field public static final int Widget_Quantum_Light_WebTextView = 16974534; // 0x10302c6
+    field public static final int Widget_Quantum_Light_WebView = 16974535; // 0x10302c7
     field public static final int Widget_Quantum_ListPopupWindow = 16974448; // 0x1030270
     field public static final int Widget_Quantum_ListView = 16974449; // 0x1030271
     field public static final int Widget_Quantum_ListView_DropDown = 16974450; // 0x1030272
     field public static final int Widget_Quantum_MediaRouteButton = 16974451; // 0x1030273
     field public static final int Widget_Quantum_PopupMenu = 16974452; // 0x1030274
-    field public static final int Widget_Quantum_PopupWindow = 16974453; // 0x1030275
-    field public static final int Widget_Quantum_ProgressBar = 16974454; // 0x1030276
-    field public static final int Widget_Quantum_ProgressBar_Horizontal = 16974455; // 0x1030277
-    field public static final int Widget_Quantum_ProgressBar_Large = 16974456; // 0x1030278
-    field public static final int Widget_Quantum_ProgressBar_Small = 16974457; // 0x1030279
-    field public static final int Widget_Quantum_ProgressBar_Small_Title = 16974458; // 0x103027a
-    field public static final int Widget_Quantum_RatingBar = 16974459; // 0x103027b
-    field public static final int Widget_Quantum_RatingBar_Indicator = 16974460; // 0x103027c
-    field public static final int Widget_Quantum_RatingBar_Small = 16974461; // 0x103027d
-    field public static final int Widget_Quantum_ScrollView = 16974462; // 0x103027e
-    field public static final int Widget_Quantum_SeekBar = 16974463; // 0x103027f
-    field public static final int Widget_Quantum_SegmentedButton = 16974464; // 0x1030280
-    field public static final int Widget_Quantum_Spinner = 16974466; // 0x1030282
-    field public static final int Widget_Quantum_StackView = 16974465; // 0x1030281
-    field public static final int Widget_Quantum_Tab = 16974467; // 0x1030283
-    field public static final int Widget_Quantum_TabWidget = 16974468; // 0x1030284
-    field public static final int Widget_Quantum_TextView = 16974469; // 0x1030285
-    field public static final int Widget_Quantum_TextView_SpinnerItem = 16974470; // 0x1030286
-    field public static final int Widget_Quantum_WebTextView = 16974471; // 0x1030287
-    field public static final int Widget_Quantum_WebView = 16974472; // 0x1030288
+    field public static final int Widget_Quantum_PopupMenu_Overflow = 16974453; // 0x1030275
+    field public static final int Widget_Quantum_PopupWindow = 16974454; // 0x1030276
+    field public static final int Widget_Quantum_ProgressBar = 16974455; // 0x1030277
+    field public static final int Widget_Quantum_ProgressBar_Horizontal = 16974456; // 0x1030278
+    field public static final int Widget_Quantum_ProgressBar_Large = 16974457; // 0x1030279
+    field public static final int Widget_Quantum_ProgressBar_Small = 16974458; // 0x103027a
+    field public static final int Widget_Quantum_ProgressBar_Small_Title = 16974459; // 0x103027b
+    field public static final int Widget_Quantum_RatingBar = 16974460; // 0x103027c
+    field public static final int Widget_Quantum_RatingBar_Indicator = 16974461; // 0x103027d
+    field public static final int Widget_Quantum_RatingBar_Small = 16974462; // 0x103027e
+    field public static final int Widget_Quantum_ScrollView = 16974463; // 0x103027f
+    field public static final int Widget_Quantum_SeekBar = 16974464; // 0x1030280
+    field public static final int Widget_Quantum_SegmentedButton = 16974465; // 0x1030281
+    field public static final int Widget_Quantum_Spinner = 16974467; // 0x1030283
+    field public static final int Widget_Quantum_StackView = 16974466; // 0x1030282
+    field public static final int Widget_Quantum_Tab = 16974468; // 0x1030284
+    field public static final int Widget_Quantum_TabWidget = 16974469; // 0x1030285
+    field public static final int Widget_Quantum_TextView = 16974470; // 0x1030286
+    field public static final int Widget_Quantum_TextView_SpinnerItem = 16974471; // 0x1030287
+    field public static final int Widget_Quantum_WebTextView = 16974472; // 0x1030288
+    field public static final int Widget_Quantum_WebView = 16974473; // 0x1030289
     field public static final int Widget_RatingBar = 16973857; // 0x1030021
     field public static final int Widget_ScrollView = 16973869; // 0x103002d
     field public static final int Widget_SeekBar = 16973856; // 0x1030020
@@ -25131,23 +25134,53 @@
   public class VoiceInteractionService extends android.app.Service {
     ctor public VoiceInteractionService();
     method public android.os.IBinder onBind(android.content.Intent);
-    method public void startVoiceActivity(android.content.Intent, android.os.Bundle);
+    method public void startSession(android.os.Bundle);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
     field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
   }
 
-  public abstract class VoiceInteractionSession {
+  public abstract class VoiceInteractionSession implements android.view.KeyEvent.Callback {
     ctor public VoiceInteractionSession(android.content.Context);
     ctor public VoiceInteractionSession(android.content.Context, android.os.Handler);
+    method public void finish();
+    method public android.view.LayoutInflater getLayoutInflater();
+    method public android.app.Dialog getWindow();
+    method public void hideWindow();
+    method public void onBackPressed();
     method public abstract void onCancel(android.service.voice.VoiceInteractionSession.Request);
+    method public void onCloseSystemDialogs();
     method public abstract void onCommand(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
+    method public void onComputeInsets(android.service.voice.VoiceInteractionSession.Insets);
     method public abstract void onConfirm(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
+    method public void onCreate(android.os.Bundle);
+    method public android.view.View onCreateContentView();
+    method public void onDestroy();
     method public abstract boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
+    method public boolean onKeyDown(int, android.view.KeyEvent);
+    method public boolean onKeyLongPress(int, android.view.KeyEvent);
+    method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
+    method public boolean onKeyUp(int, android.view.KeyEvent);
+    method public void onTaskFinished(android.content.Intent, int);
+    method public void onTaskStarted(android.content.Intent, int);
+    method public void setContentView(android.view.View);
+    method public void setTheme(int);
+    method public void showWindow();
+    method public void startVoiceActivity(android.content.Intent);
   }
 
   public static class VoiceInteractionSession.Caller {
   }
 
+  public static final class VoiceInteractionSession.Insets {
+    ctor public VoiceInteractionSession.Insets();
+    field public static final int TOUCHABLE_INSETS_CONTENT = 1; // 0x1
+    field public static final int TOUCHABLE_INSETS_FRAME = 0; // 0x0
+    field public static final int TOUCHABLE_INSETS_REGION = 3; // 0x3
+    field public int contentTopInsets;
+    field public int touchableInsets;
+    field public final android.graphics.Region touchableRegion;
+  }
+
   public static class VoiceInteractionSession.Request {
     method public void sendCancelResult();
     method public void sendCommandResult(boolean, android.os.Bundle);
@@ -30950,7 +30983,6 @@
   public class ViewConfiguration {
     ctor public deprecated ViewConfiguration();
     method public static android.view.ViewConfiguration get(android.content.Context);
-    method public long getDeviceGlobalActionKeyTimeout();
     method public static int getDoubleTapTimeout();
     method public static deprecated int getEdgeSlop();
     method public static deprecated int getFadingEdgeLength();
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 3c1455b..3eb2fea 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Handler;
@@ -30,6 +31,7 @@
 import android.transition.TransitionSet;
 import android.util.ArrayMap;
 import android.util.Pair;
+import android.util.SparseArray;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroupOverlay;
@@ -138,6 +140,10 @@
     private static final String KEY_HEIGHT = "shared_element:height";
     private static final String KEY_NAME = "shared_element:name";
     private static final String KEY_BITMAP = "shared_element:bitmap";
+    private static final String KEY_SCALE_TYPE = "shared_element:scaleType";
+    private static final String KEY_IMAGE_MATRIX = "shared_element:imageMatrix";
+
+    private static final ImageView.ScaleType[] SCALE_TYPE_VALUES = ImageView.ScaleType.values();
 
     /**
      * Sent by the exiting coordinator (either EnterTransitionCoordinator
@@ -322,7 +328,8 @@
         final ArrayList<View> accepted = new ArrayList<View>();
         final ArrayList<View> rejected = new ArrayList<View>();
         createSharedElementImages(accepted, rejected, sharedElementNames, state);
-        setSharedElementState(state, accepted);
+        ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageViewState =
+                setSharedElementState(state, accepted);
         handleRejected(rejected);
 
         if (getViewsTransition() != null) {
@@ -331,6 +338,7 @@
         setViewVisibility(mSharedElements, View.VISIBLE);
         Transition transition = beginTransition(mEnteringViews, true, allowOverlappingTransitions(),
                 true);
+        setOriginalImageViewState(originalImageViewState);
 
         if (allowOverlappingTransitions()) {
             onStartEnterTransition(transition, mEnteringViews);
@@ -568,15 +576,22 @@
         mEpicenterCallback.setEpicenter(epicenter);
     }
 
-    private void setSharedElementState(Bundle sharedElementState,
-            final ArrayList<View> acceptedOverlayViews) {
+    private ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> setSharedElementState(
+            Bundle sharedElementState, final ArrayList<View> acceptedOverlayViews) {
+        ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageState =
+                new ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>>();
         final int[] tempLoc = new int[2];
         if (sharedElementState != null) {
             for (int i = 0; i < mSharedElements.size(); i++) {
                 View sharedElement = mSharedElements.get(i);
+                String name = mTargetSharedNames.get(i);
+                Pair<ImageView.ScaleType, Matrix> originalState = getOldImageState(sharedElement,
+                        name, sharedElementState);
+                if (originalState != null) {
+                    originalImageState.put((ImageView) sharedElement, originalState);
+                }
                 View parent = (View) sharedElement.getParent();
                 parent.getLocationOnScreen(tempLoc);
-                String name = mTargetSharedNames.get(i);
                 setSharedElementState(sharedElement, name, sharedElementState, tempLoc);
                 sharedElement.requestLayout();
             }
@@ -596,6 +611,29 @@
                     }
                 }
         );
+        return originalImageState;
+    }
+
+    private static Pair<ImageView.ScaleType, Matrix> getOldImageState(View view, String name,
+            Bundle transitionArgs) {
+        if (!(view instanceof ImageView)) {
+            return null;
+        }
+        Bundle bundle = transitionArgs.getBundle(name);
+        int scaleTypeInt = bundle.getInt(KEY_SCALE_TYPE, -1);
+        if (scaleTypeInt < 0) {
+            return null;
+        }
+
+        ImageView imageView = (ImageView) view;
+        ImageView.ScaleType originalScaleType = imageView.getScaleType();
+
+        Matrix originalMatrix = null;
+        if (originalScaleType == ImageView.ScaleType.MATRIX) {
+            originalMatrix = new Matrix(imageView.getImageMatrix());
+        }
+
+        return Pair.create(originalScaleType, originalMatrix);
     }
 
     /**
@@ -614,6 +652,21 @@
             return;
         }
 
+        if (view instanceof ImageView) {
+            int scaleTypeInt = sharedElementBundle.getInt(KEY_SCALE_TYPE, -1);
+            if (scaleTypeInt >= 0) {
+                ImageView imageView = (ImageView) view;
+                ImageView.ScaleType scaleType = SCALE_TYPE_VALUES[scaleTypeInt];
+                imageView.setScaleType(scaleType);
+                if (scaleType == ImageView.ScaleType.MATRIX) {
+                    float[] matrixValues = sharedElementBundle.getFloatArray(KEY_IMAGE_MATRIX);
+                    Matrix matrix = new Matrix();
+                    matrix.setValues(matrixValues);
+                    imageView.setImageMatrix(matrix);
+                }
+            }
+        }
+
         float z = sharedElementBundle.getFloat(KEY_TRANSLATION_Z);
         view.setTranslationZ(z);
 
@@ -666,6 +719,17 @@
         view.draw(canvas);
         sharedElementBundle.putParcelable(KEY_BITMAP, bitmap);
 
+        if (view instanceof ImageView) {
+            ImageView imageView = (ImageView) view;
+            int scaleTypeInt = scaleTypeToInt(imageView.getScaleType());
+            sharedElementBundle.putInt(KEY_SCALE_TYPE, scaleTypeInt);
+            if (imageView.getScaleType() == ImageView.ScaleType.MATRIX) {
+                float[] matrix = new float[9];
+                imageView.getImageMatrix().getValues(matrix);
+                sharedElementBundle.putFloatArray(KEY_IMAGE_MATRIX, matrix);
+            }
+        }
+
         transitionArgs.putBundle(name, sharedElementBundle);
     }
 
@@ -829,6 +893,25 @@
         }
     }
 
+    private static void setOriginalImageViewState(
+            ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalState) {
+        for (int i = 0; i < originalState.size(); i++) {
+            ImageView imageView = originalState.keyAt(i);
+            Pair<ImageView.ScaleType, Matrix> state = originalState.valueAt(i);
+            imageView.setScaleType(state.first);
+            imageView.setImageMatrix(state.second);
+        }
+    }
+
+    private static int scaleTypeToInt(ImageView.ScaleType scaleType) {
+        for (int i = 0; i < SCALE_TYPE_VALUES.length; i++) {
+            if (scaleType == SCALE_TYPE_VALUES[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
     private static class FixedEpicenterCallback extends Transition.EpicenterCallback {
         private Rect mEpicenter;
 
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index a810134..097c64e 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -33,6 +33,7 @@
 import android.view.Surface;
 import android.view.TextureView;
 import android.view.TextureView.SurfaceTextureListener;
+import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import dalvik.system.CloseGuard;
@@ -51,6 +52,7 @@
     private int mWidth;
     private int mHeight;
     private Surface mSurface;
+    private int mLastVisibility;
 
     // Only one IIntentSender or Intent may be queued at a time. Most recent one wins.
     IIntentSender mQueuedPendingIntent;
@@ -95,6 +97,8 @@
         mMetrics = new DisplayMetrics();
         wm.getDefaultDisplay().getMetrics(mMetrics);
 
+        mLastVisibility = getVisibility();
+
         if (DEBUG) Log.v(TAG, "ctor()");
     }
 
@@ -103,6 +107,26 @@
         mTextureView.layout(0, 0, r - l, b - t);
     }
 
+    @Override
+    protected void onVisibilityChanged(View changedView, int visibility) {
+        super.onVisibilityChanged(changedView, visibility);
+
+        if (mSurface != null) {
+            try {
+                if (visibility == View.GONE) {
+                    mActivityContainer.setSurface(null, mWidth, mHeight, mMetrics.densityDpi);
+                } else if (mLastVisibility == View.GONE) {
+                    // Don't change surface when going between View.VISIBLE and View.INVISIBLE.
+                    mActivityContainer.setSurface(mSurface, mWidth, mHeight, mMetrics.densityDpi);
+                }
+            } catch (RemoteException e) {
+                throw new RuntimeException(
+                        "ActivityView: Unable to set surface of ActivityContainer. " + e);
+            }
+        }
+        mLastVisibility = visibility;
+    }
+
     private boolean injectInputEvent(InputEvent event) {
         return mActivityContainer != null && mActivityContainer.injectEvent(event);
     }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index a4b2651..fe532bf 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -473,14 +473,14 @@
         registerService(NOTIFICATION_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
                     final Context outerContext = ctx.getOuterContext();
-                    // TODO: Why are we not just using the theme attribute
-                    // that defines the dialog theme?
                     return new NotificationManager(
                         new ContextThemeWrapper(outerContext,
-                                outerContext.getResources().selectSystemTheme(0,
+                                Resources.selectSystemTheme(0,
                                         outerContext.getApplicationInfo().targetSdkVersion,
-                                        com.android.internal.R.array.system_theme_sdks,
-                                        com.android.internal.R.array.system_theme_dialog_styles)),
+                                        com.android.internal.R.style.Theme_Dialog,
+                                        com.android.internal.R.style.Theme_Holo_Dialog,
+                                        com.android.internal.R.style.Theme_DeviceDefault_Dialog,
+                                        com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog)),
                         ctx.mMainThread.getHandler());
                 }});
 
@@ -731,7 +731,7 @@
     @Override
     public Resources.Theme getTheme() {
         if (mTheme == null) {
-            mThemeResource = mResources.selectDefaultTheme(mThemeResource,
+            mThemeResource = Resources.selectDefaultTheme(mThemeResource,
                     getOuterContext().getApplicationInfo().targetSdkVersion);
             mTheme = mResources.newTheme();
             mTheme.applyStyle(mThemeResource, true);
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 1331777..499de17 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -137,45 +137,42 @@
 
     /**
      * Returns the most appropriate default theme for the specified target SDK version.
+     * <ul>
+     * <li>Below API 11: Gingerbread
+     * <li>APIs 11 thru 14: Holo
+     * <li>APIs 14 thru XX: Device default dark
+     * <li>API XX and above: Device default light with dark action bar
+     * </ul>
      *
      * @param curTheme The current theme, or 0 if not specified.
      * @param targetSdkVersion The target SDK version.
      * @return A theme resource identifier
      * @hide
      */
-    public int selectDefaultTheme(int curTheme, int targetSdkVersion) {
+    public static int selectDefaultTheme(int curTheme, int targetSdkVersion) {
         return selectSystemTheme(curTheme, targetSdkVersion,
-                com.android.internal.R.array.system_theme_sdks,
-                com.android.internal.R.array.system_theme_styles);
+                com.android.internal.R.style.Theme,
+                com.android.internal.R.style.Theme_Holo,
+                com.android.internal.R.style.Theme_DeviceDefault,
+                com.android.internal.R.style.Theme_DeviceDefault_Light_DarkActionBar);
     }
 
-    /**
-     * Returns the most appropriate default theme for the specified target SDK version.
-     *
-     * @param curTheme The current theme, or 0 if not specified.
-     * @param targetSdkVersion The target SDK version.
-     * @param sdkArrayId Identifier for integer array resource containing
-     *        sorted minimum SDK versions. First entry must be 0.
-     * @param themeArrayId Identifier for array resource containing the
-     *        default themes that map to SDK versions.
-     * @return A theme resource identifier
-     * @hide
-     */
-    public int selectSystemTheme(
-            int curTheme, int targetSdkVersion, int sdkArrayId, int themeArrayId) {
+    /** @hide */
+    public static int selectSystemTheme(int curTheme, int targetSdkVersion, int orig, int holo,
+            int dark, int deviceDefault) {
         if (curTheme != 0) {
             return curTheme;
         }
-
-        final int[] targetSdks = getIntArray(sdkArrayId);
-        final TypedArray defaultThemes = obtainTypedArray(themeArrayId);
-        for (int i = targetSdks.length - 1; i > 0; i--) {
-            if (targetSdkVersion >= targetSdks[i]) {
-                return defaultThemes.getResourceId(i, 0);
-            }
+        if (targetSdkVersion < Build.VERSION_CODES.HONEYCOMB) {
+            return orig;
         }
-
-        return defaultThemes.getResourceId(0, 0);
+        if (targetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            return holo;
+        }
+        if (targetSdkVersion < Build.VERSION_CODES.CUR_DEVELOPMENT) {
+            return dark;
+        }
+        return deviceDefault;
     }
 
     /**
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index e6dbcd0..f6438b4 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -654,17 +654,20 @@
         return false;
     }
 
-    @Override
-    public void onCreate() {
-        mTheme = getResources().selectSystemTheme(mTheme, getApplicationInfo().targetSdkVersion,
-                com.android.internal.R.array.system_theme_sdks,
-                com.android.internal.R.array.system_theme_ime_styles);
+    @Override public void onCreate() {
+        mTheme = Resources.selectSystemTheme(mTheme,
+                getApplicationInfo().targetSdkVersion,
+                android.R.style.Theme_InputMethod,
+                android.R.style.Theme_Holo_InputMethod,
+                android.R.style.Theme_DeviceDefault_InputMethod,
+                android.R.style.Theme_DeviceDefault_InputMethod);
         super.setTheme(mTheme);
         super.onCreate();
         mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
         mInflater = (LayoutInflater)getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
-        mWindow = new SoftInputWindow(this, mTheme, mDispatcherState);
+        mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
+                false);
         if (mHardwareAccelerated) {
             mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
         }
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index df1afee..a9bace1 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -30,11 +30,20 @@
  * method window.  It will be displayed along the edge of the screen, moving
  * the application user interface away from it so that the focused item is
  * always visible.
+ * @hide
  */
-class SoftInputWindow extends Dialog {
+public class SoftInputWindow extends Dialog {
+    final String mName;
+    final Callback mCallback;
+    final KeyEvent.Callback mKeyEventCallback;
     final KeyEvent.DispatcherState mDispatcherState;
+    final boolean mTakesFocus;
     private final Rect mBounds = new Rect();
-    
+
+    public interface Callback {
+        public void onBackPressed();
+    }
+
     public void setToken(IBinder token) {
         WindowManager.LayoutParams lp = getWindow().getAttributes();
         lp.token = token;
@@ -53,10 +62,15 @@
      *        using styles. This theme is applied on top of the current theme in
      *        <var>context</var>. If 0, the default dialog theme will be used.
      */
-    public SoftInputWindow(Context context, int theme,
-            KeyEvent.DispatcherState dispatcherState) {
+    public SoftInputWindow(Context context, String name, int theme, Callback callback,
+            KeyEvent.Callback keyEventCallback, KeyEvent.DispatcherState dispatcherState,
+            boolean takesFocus) {
         super(context, theme);
+        mName = name;
+        mCallback = callback;
+        mKeyEventCallback = keyEventCallback;
         mDispatcherState = dispatcherState;
+        mTakesFocus = takesFocus;
         initDockWindow();
     }
 
@@ -148,11 +162,47 @@
         }
     }
 
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (mKeyEventCallback != null && mKeyEventCallback.onKeyDown(keyCode, event)) {
+            return true;
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+
+    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+        if (mKeyEventCallback != null && mKeyEventCallback.onKeyLongPress(keyCode, event)) {
+            return true;
+        }
+        return super.onKeyLongPress(keyCode, event);
+    }
+
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (mKeyEventCallback != null && mKeyEventCallback.onKeyUp(keyCode, event)) {
+            return true;
+        }
+        return super.onKeyUp(keyCode, event);
+    }
+
+    public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
+        if (mKeyEventCallback != null && mKeyEventCallback.onKeyMultiple(keyCode, count, event)) {
+            return true;
+        }
+        return super.onKeyMultiple(keyCode, count, event);
+    }
+
+    public void onBackPressed() {
+        if (mCallback != null) {
+            mCallback.onBackPressed();
+        } else {
+            super.onBackPressed();
+        }
+    }
+
     private void initDockWindow() {
         WindowManager.LayoutParams lp = getWindow().getAttributes();
 
         lp.type = WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-        lp.setTitle("InputMethod");
+        lp.setTitle(mName);
 
         lp.gravity = Gravity.BOTTOM;
         lp.width = -1;
@@ -161,11 +211,19 @@
         //lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
 
         getWindow().setAttributes(lp);
-        getWindow().setFlags(
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
+
+        int windowSetFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+        int windowModFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
-                WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+                WindowManager.LayoutParams.FLAG_DIM_BEHIND;
+
+        if (!mTakesFocus) {
+            windowSetFlags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        } else {
+            windowSetFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+            windowModFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+        }
+
+        getWindow().setFlags(windowSetFlags, windowModFlags);
     }
 }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index f1ad1f8..63a7bb7 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2899,7 +2899,7 @@
             }
         }
         if (!didWake && wakelockTag != null) {
-            pw.print(longNames ? "wake_lock=" : "w=");
+            pw.print(longNames ? " wake_lock=" : ",w=");
             if (longNames) {
                 UserHandle.formatUid(pw, wakelockTag.uid);
                 pw.print(":\"");
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 72720d1..e7cdc4e 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -87,7 +87,7 @@
     }
 
     private String key() {
-        return pkg + '|' + id + '|' + tag + '|' + uid;
+        return user.getIdentifier() + "|" + pkg + "|" + id + "|" + tag + "|" + uid;
     }
 
     public void writeToParcel(Parcel out, int flags) {
diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl
index 7dbf66b..9f9c312 100644
--- a/core/java/android/service/voice/IVoiceInteractionSession.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl
@@ -16,13 +16,14 @@
 
 package android.service.voice;
 
-import android.os.Bundle;
-
-import com.android.internal.app.IVoiceInteractorCallback;
-import com.android.internal.app.IVoiceInteractorRequest;
+import android.content.Intent;
 
 /**
  * @hide
  */
-interface IVoiceInteractionSession {
+oneway interface IVoiceInteractionSession {
+    void taskStarted(in Intent intent, int taskId);
+    void taskFinished(in Intent intent, int taskId);
+    void closeSystemDialogs();
+    void destroy();
 }
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index d005890..e15489b 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -27,6 +27,19 @@
 import android.os.ServiceManager;
 import com.android.internal.app.IVoiceInteractionManagerService;
 
+/**
+ * Top-level service of the current global voice interactor, which is providing
+ * support for hotwording, the back-end of a {@link android.app.VoiceInteractor}, etc.
+ * The current VoiceInteractionService that has been selected by the user is kept
+ * always running by the system, to allow it to do things like listen for hotwords
+ * in the background to instigate voice interactions.
+ *
+ * <p>Because this service is always running, it should be kept as lightweight as
+ * possible.  Heavy-weight operations (including showing UI) should be implemented
+ * in the associated {@link android.service.voice.VoiceInteractionSessionService} when
+ * an actual voice interaction is taking place, and that service should run in a
+ * separate process from this one.
+ */
 public class VoiceInteractionService extends Service {
     /**
      * The {@link Intent} that must be declared as handled by the service.
@@ -51,11 +64,9 @@
 
     IVoiceInteractionManagerService mSystemService;
 
-    public void startVoiceActivity(Intent intent, Bundle sessionArgs) {
+    public void startSession(Bundle args) {
         try {
-            mSystemService.startVoiceActivity(intent,
-                    intent.resolveType(getContentResolver()),
-                    mInterface, sessionArgs);
+            mSystemService.startSession(mInterface, args);
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 963b6b4..a83544d 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -16,7 +16,14 @@
 
 package android.service.voice;
 
+import android.app.Dialog;
+import android.app.Instrumentation;
 import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Region;
+import android.inputmethodservice.SoftInputWindow;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -25,16 +32,53 @@
 import android.os.RemoteException;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import com.android.internal.app.IVoiceInteractionManagerService;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.IVoiceInteractorCallback;
 import com.android.internal.app.IVoiceInteractorRequest;
 import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.SomeArgs;
 
-public abstract class VoiceInteractionSession {
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+public abstract class VoiceInteractionSession implements KeyEvent.Callback {
     static final String TAG = "VoiceInteractionSession";
     static final boolean DEBUG = true;
 
+    final Context mContext;
+    final HandlerCaller mHandlerCaller;
+
+    final KeyEvent.DispatcherState mDispatcherState = new KeyEvent.DispatcherState();
+
+    IVoiceInteractionManagerService mSystemService;
+    IBinder mToken;
+
+    int mTheme = 0;
+    LayoutInflater mInflater;
+    TypedArray mThemeAttrs;
+    View mRootView;
+    FrameLayout mContentFrame;
+    SoftInputWindow mWindow;
+
+    boolean mInitialized;
+    boolean mWindowAdded;
+    boolean mWindowVisible;
+    boolean mWindowWasVisible;
+    boolean mInShowWindow;
+
+    final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>();
+
+    final Insets mTmpInsets = new Insets();
+    final int[] mTmpLocation = new int[2];
+
     final IVoiceInteractor mInteractor = new IVoiceInteractor.Stub() {
         @Override
         public IVoiceInteractorRequest startConfirmation(String callingPackage,
@@ -71,6 +115,27 @@
     };
 
     final IVoiceInteractionSession mSession = new IVoiceInteractionSession.Stub() {
+        @Override
+        public void taskStarted(Intent intent, int taskId) {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_STARTED,
+                    taskId, intent));
+        }
+
+        @Override
+        public void taskFinished(Intent intent, int taskId) {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_FINISHED,
+                    taskId, intent));
+        }
+
+        @Override
+        public void closeSystemDialogs() {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_CLOSE_SYSTEM_DIALOGS));
+        }
+
+        @Override
+        public void destroy() {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DESTROY));
+        }
     };
 
     public static class Request {
@@ -129,38 +194,128 @@
     static final int MSG_SUPPORTS_COMMANDS = 3;
     static final int MSG_CANCEL = 4;
 
-    final Context mContext;
-    final HandlerCaller mHandlerCaller;
-    final HandlerCaller.Callback mHandlerCallerCallback = new HandlerCaller.Callback() {
+    static final int MSG_TASK_STARTED = 100;
+    static final int MSG_TASK_FINISHED = 101;
+    static final int MSG_CLOSE_SYSTEM_DIALOGS = 102;
+    static final int MSG_DESTROY = 103;
+
+    class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback {
         @Override
         public void executeMessage(Message msg) {
-            SomeArgs args = (SomeArgs)msg.obj;
+            SomeArgs args;
             switch (msg.what) {
                 case MSG_START_CONFIRMATION:
+                    args = (SomeArgs)msg.obj;
                     if (DEBUG) Log.d(TAG, "onConfirm: req=" + ((Request) args.arg2).mInterface
                             + " prompt=" + args.arg3 + " extras=" + args.arg4);
                     onConfirm((Caller)args.arg1, (Request)args.arg2, (String)args.arg3,
                             (Bundle)args.arg4);
                     break;
                 case MSG_START_COMMAND:
+                    args = (SomeArgs)msg.obj;
                     if (DEBUG) Log.d(TAG, "onCommand: req=" + ((Request) args.arg2).mInterface
                             + " command=" + args.arg3 + " extras=" + args.arg4);
                     onCommand((Caller) args.arg1, (Request) args.arg2, (String) args.arg3,
                             (Bundle) args.arg4);
                     break;
                 case MSG_SUPPORTS_COMMANDS:
+                    args = (SomeArgs)msg.obj;
                     if (DEBUG) Log.d(TAG, "onGetSupportedCommands: cmds=" + args.arg2);
                     args.arg1 = onGetSupportedCommands((Caller) args.arg1, (String[]) args.arg2);
                     break;
                 case MSG_CANCEL:
+                    args = (SomeArgs)msg.obj;
                     if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request) args.arg1).mInterface);
                     onCancel((Request)args.arg1);
                     break;
+                case MSG_TASK_STARTED:
+                    if (DEBUG) Log.d(TAG, "onTaskStarted: intent=" + msg.obj
+                            + " taskId=" + msg.arg1);
+                    onTaskStarted((Intent) msg.obj, msg.arg1);
+                    break;
+                case MSG_TASK_FINISHED:
+                    if (DEBUG) Log.d(TAG, "onTaskFinished: intent=" + msg.obj
+                            + " taskId=" + msg.arg1);
+                    onTaskFinished((Intent) msg.obj, msg.arg1);
+                    break;
+                case MSG_CLOSE_SYSTEM_DIALOGS:
+                    if (DEBUG) Log.d(TAG, "onCloseSystemDialogs");
+                    onCloseSystemDialogs();
+                    break;
+                case MSG_DESTROY:
+                    if (DEBUG) Log.d(TAG, "doDestroy");
+                    doDestroy();
+                    break;
             }
         }
-    };
 
-    final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>();
+        @Override
+        public void onBackPressed() {
+            VoiceInteractionSession.this.onBackPressed();
+        }
+    }
+
+    final MyCallbacks mCallbacks = new MyCallbacks();
+
+    /**
+     * Information about where interesting parts of the input method UI appear.
+     */
+    public static final class Insets {
+        /**
+         * This is the top part of the UI that is the main content.  It is
+         * used to determine the basic space needed, to resize/pan the
+         * application behind.  It is assumed that this inset does not
+         * change very much, since any change will cause a full resize/pan
+         * of the application behind.  This value is relative to the top edge
+         * of the input method window.
+         */
+        public int contentTopInsets;
+
+        /**
+         * This is the region of the UI that is touchable.  It is used when
+         * {@link #touchableInsets} is set to {@link #TOUCHABLE_INSETS_REGION}.
+         * The region should be specified relative to the origin of the window frame.
+         */
+        public final Region touchableRegion = new Region();
+
+        /**
+         * Option for {@link #touchableInsets}: the entire window frame
+         * can be touched.
+         */
+        public static final int TOUCHABLE_INSETS_FRAME
+                = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
+
+        /**
+         * Option for {@link #touchableInsets}: the area inside of
+         * the content insets can be touched.
+         */
+        public static final int TOUCHABLE_INSETS_CONTENT
+                = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
+
+        /**
+         * Option for {@link #touchableInsets}: the region specified by
+         * {@link #touchableRegion} can be touched.
+         */
+        public static final int TOUCHABLE_INSETS_REGION
+                = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
+
+        /**
+         * Determine which area of the window is touchable by the user.  May
+         * be one of: {@link #TOUCHABLE_INSETS_FRAME},
+         * {@link #TOUCHABLE_INSETS_CONTENT}, or {@link #TOUCHABLE_INSETS_REGION}.
+         */
+        public int touchableInsets;
+    }
+
+    final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
+            new ViewTreeObserver.OnComputeInternalInsetsListener() {
+        public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
+            onComputeInsets(mTmpInsets);
+            info.contentInsets.top = info.visibleInsets.top = mTmpInsets.contentTopInsets;
+            info.touchableRegion.set(mTmpInsets.touchableRegion);
+            info.setTouchableInsets(mTmpInsets.touchableInsets);
+        }
+    };
 
     public VoiceInteractionSession(Context context) {
         this(context, new Handler());
@@ -169,7 +324,7 @@
     public VoiceInteractionSession(Context context, Handler handler) {
         mContext = context;
         mHandlerCaller = new HandlerCaller(context, handler.getLooper(),
-                mHandlerCallerCallback, true);
+                mCallbacks, true);
     }
 
     Request findRequest(IVoiceInteractorCallback callback, boolean newRequest) {
@@ -188,6 +343,192 @@
         }
     }
 
+    void doCreate(IVoiceInteractionManagerService service, IBinder token, Bundle args) {
+        mSystemService = service;
+        mToken = token;
+        onCreate(args);
+    }
+
+    void doDestroy() {
+        if (mInitialized) {
+            mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
+                    mInsetsComputer);
+            if (mWindowAdded) {
+                mWindow.dismiss();
+                mWindowAdded = false;
+            }
+            mInitialized = false;
+        }
+    }
+
+    void initViews() {
+        mInitialized = true;
+
+        mThemeAttrs = mContext.obtainStyledAttributes(android.R.styleable.VoiceInteractionSession);
+        mRootView = mInflater.inflate(
+                com.android.internal.R.layout.voice_interaction_session, null);
+        mRootView.setSystemUiVisibility(
+                View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+        mWindow.setContentView(mRootView);
+        mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
+
+        mContentFrame = (FrameLayout)mRootView.findViewById(android.R.id.content);
+    }
+
+    public void showWindow() {
+        if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded
+                + " mWindowVisible=" + mWindowVisible);
+
+        if (mInShowWindow) {
+            Log.w(TAG, "Re-entrance in to showWindow");
+            return;
+        }
+
+        try {
+            mInShowWindow = true;
+            if (!mWindowVisible) {
+                mWindowVisible = true;
+                if (!mWindowAdded) {
+                    mWindowAdded = true;
+                    View v = onCreateContentView();
+                    if (v != null) {
+                        setContentView(v);
+                    }
+                }
+                mWindow.show();
+            }
+        } finally {
+            mWindowWasVisible = true;
+            mInShowWindow = false;
+        }
+    }
+
+    public void hideWindow() {
+        if (mWindowVisible) {
+            mWindow.hide();
+            mWindowVisible = false;
+        }
+    }
+
+    /**
+     * You can call this to customize the theme used by your IME's window.
+     * This must be set before {@link #onCreate}, so you
+     * will typically call it in your constructor with the resource ID
+     * of your custom theme.
+     */
+    public void setTheme(int theme) {
+        if (mWindow != null) {
+            throw new IllegalStateException("Must be called before onCreate()");
+        }
+        mTheme = theme;
+    }
+
+    public void startVoiceActivity(Intent intent) {
+        if (mToken == null) {
+            throw new IllegalStateException("Can't call before onCreate()");
+        }
+        try {
+            int res = mSystemService.startVoiceActivity(mToken, intent,
+                    intent.resolveType(mContext.getContentResolver()));
+            Instrumentation.checkStartActivityResult(res, intent);
+        } catch (RemoteException e) {
+        }
+    }
+
+    public LayoutInflater getLayoutInflater() {
+        return mInflater;
+    }
+
+    public Dialog getWindow() {
+        return mWindow;
+    }
+
+    public void finish() {
+        if (mToken == null) {
+            throw new IllegalStateException("Can't call before onCreate()");
+        }
+        hideWindow();
+        try {
+            mSystemService.finish(mToken);
+        } catch (RemoteException e) {
+        }
+    }
+
+    public void onCreate(Bundle args) {
+        mTheme = mTheme != 0 ? mTheme
+                : com.android.internal.R.style.Theme_DeviceDefault_VoiceInteractionSession;
+        mInflater = (LayoutInflater)mContext.getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+        mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme,
+                mCallbacks, this, mDispatcherState, true);
+        mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
+        initViews();
+        mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
+        mWindow.setToken(mToken);
+    }
+
+    public void onDestroy() {
+    }
+
+    public View onCreateContentView() {
+        return null;
+    }
+
+    public void setContentView(View view) {
+        mContentFrame.removeAllViews();
+        mContentFrame.addView(view, new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT));
+
+    }
+
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        return false;
+    }
+
+    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+        return false;
+    }
+
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        return false;
+    }
+
+    public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
+        return false;
+    }
+
+    public void onBackPressed() {
+        finish();
+    }
+
+    public void onCloseSystemDialogs() {
+        finish();
+    }
+
+    /**
+     * Compute the interesting insets into your UI.  The default implementation
+     * uses the entire window frame as the insets.  The default touchable
+     * insets are {@link Insets#TOUCHABLE_INSETS_FRAME}.
+     *
+     * @param outInsets Fill in with the current UI insets.
+     */
+    public void onComputeInsets(Insets outInsets) {
+        int[] loc = mTmpLocation;
+        View decor = getWindow().getWindow().getDecorView();
+        decor.getLocationInWindow(loc);
+        outInsets.contentTopInsets = loc[1];
+        outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_FRAME;
+        outInsets.touchableRegion.setEmpty();
+    }
+
+    public void onTaskStarted(Intent intent, int taskId) {
+    }
+
+    public void onTaskFinished(Intent intent, int taskId) {
+        finish();
+    }
+
     public abstract boolean[] onGetSupportedCommands(Caller caller, String[] commands);
     public abstract void onConfirm(Caller caller, Request request, String prompt, Bundle extras);
     public abstract void onCommand(Caller caller, Request request, String command, Bundle extras);
diff --git a/core/java/android/service/voice/VoiceInteractionSessionService.java b/core/java/android/service/voice/VoiceInteractionSessionService.java
index 40e5bba..e793849 100644
--- a/core/java/android/service/voice/VoiceInteractionSessionService.java
+++ b/core/java/android/service/voice/VoiceInteractionSessionService.java
@@ -29,11 +29,15 @@
 import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.SomeArgs;
 
+/**
+ * An active voice interaction session, initiated by a {@link VoiceInteractionService}.
+ */
 public abstract class VoiceInteractionSessionService extends Service {
 
     static final int MSG_NEW_SESSION = 1;
 
     IVoiceInteractionManagerService mSystemService;
+    VoiceInteractionSession mSession;
 
     IVoiceInteractionSessionService mInterface = new IVoiceInteractionSessionService.Stub() {
         public void newSession(IBinder token, Bundle args) {
@@ -73,9 +77,14 @@
     }
 
     void doNewSession(IBinder token, Bundle args) {
-        VoiceInteractionSession session = onNewSession(args);
+        if (mSession != null) {
+            mSession.doDestroy();
+            mSession = null;
+        }
+        mSession = onNewSession(args);
         try {
-            mSystemService.deliverNewSession(token, session.mSession, session.mInteractor);
+            mSystemService.deliverNewSession(token, mSession.mSession, mSession.mInteractor);
+            mSession.doCreate(mSystemService, token, args);
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/transition/MoveImage.java b/core/java/android/transition/MoveImage.java
index e4c3939..183cdd2 100644
--- a/core/java/android/transition/MoveImage.java
+++ b/core/java/android/transition/MoveImage.java
@@ -125,7 +125,7 @@
         Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_MATRIX);
         Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_MATRIX);
 
-        if (!startMatrix.equals(endMatrix)) {
+        if (startMatrix != null && !startMatrix.equals(endMatrix)) {
             changes.add(PropertyValuesHolder.ofObject(MatrixClippedDrawable.MATRIX_PROPERTY,
                     new MatrixEvaluator(), startMatrix, endMatrix));
         }
@@ -230,7 +230,9 @@
 
     private static void expandClip(Rect bounds, Matrix matrix, Rect clip, Rect otherClip) {
         RectF boundsF = new RectF(bounds);
-        matrix.mapRect(boundsF);
+        if (matrix != null) {
+            matrix.mapRect(boundsF);
+        }
         clip.left = expandMinDimension(boundsF.left, clip.left, otherClip.left);
         clip.top = expandMinDimension(boundsF.top, clip.top, otherClip.top);
         clip.right = expandMaxDimension(boundsF.right, clip.right, otherClip.right);
@@ -256,10 +258,20 @@
         int drawableWidth = drawable.getIntrinsicWidth();
         int drawableHeight = drawable.getIntrinsicHeight();
         ImageView.ScaleType scaleType = imageView.getScaleType();
-        if (drawableWidth <= 0 || drawableHeight <= 0 || scaleType == ImageView.ScaleType.FIT_XY) {
-            return null;
+        Matrix matrix;
+        if (drawableWidth <= 0 || drawableHeight <= 0) {
+            matrix = null;
+        } else if (scaleType == ImageView.ScaleType.FIT_XY) {
+            matrix = new Matrix();
+            float scaleX = imageView.getWidth();
+            scaleX /= drawableWidth;
+            float scaleY = imageView.getHeight();
+            scaleY /= drawableHeight;
+            matrix.setScale(scaleX, scaleY);
+        } else {
+            matrix = new Matrix(imageView.getImageMatrix());
         }
-        return new Matrix(imageView.getImageMatrix());
+        return matrix;
     }
 
     private Rect findClip(ImageView imageView) {
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index f1523ae..0a76075 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -259,6 +259,14 @@
         return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
     }
 
+    /**
+     * @return The refresh rate as the nanoseconds between frames
+     * @hide
+     */
+    long getFrameIntervalNanos() {
+        return mFrameIntervalNanos;
+    }
+
     void dump(String prefix, PrintWriter writer) {
         String innerPrefix = prefix + "  ";
         writer.print(prefix); writer.println("Choreographer:");
diff --git a/core/java/android/view/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java
index ba1c4b6..0afbde9 100644
--- a/core/java/android/view/ContextThemeWrapper.java
+++ b/core/java/android/view/ContextThemeWrapper.java
@@ -96,7 +96,7 @@
             return mTheme;
         }
 
-        mThemeResource = getResources().selectDefaultTheme(mThemeResource,
+        mThemeResource = Resources.selectDefaultTheme(mThemeResource,
                 getApplicationInfo().targetSdkVersion);
         initializeTheme();
 
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index eaec8ab..9c7fa25 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -19,7 +19,6 @@
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
-import android.os.SystemClock;
 import android.os.Trace;
 import android.view.Surface.OutOfResourcesException;
 import android.view.View.AttachInfo;
@@ -52,16 +51,29 @@
 
     private static final Rect NULL_RECT = new Rect();
 
+    private static final long NANOS_PER_MS = 1000000;
+
+    // Keep in sync with DrawFrameTask.h SYNC_* flags
+    // Nothing interesting to report
+    private static final int SYNC_OK = 0x0;
+    // Needs a ViewRoot invalidate
+    private static final int SYNC_INVALIDATE_REQUIRED = 0x1;
+
     private int mWidth, mHeight;
     private long mNativeProxy;
     private boolean mInitialized = false;
     private RenderNode mRootNode;
+    private Choreographer mChoreographer;
 
     ThreadedRenderer(boolean translucent) {
         long rootNodePtr = nCreateRootRenderNode();
         mRootNode = RenderNode.adopt(rootNodePtr);
         mRootNode.setClipToBounds(false);
         mNativeProxy = nCreateProxy(translucent, rootNodePtr);
+
+        // Setup timing
+        mChoreographer = Choreographer.getInstance();
+        nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos());
     }
 
     @Override
@@ -161,15 +173,6 @@
         return false;
     }
 
-    /**
-     * TODO: Remove
-     * Temporary hack to allow RenderThreadTest prototype app to trigger
-     * replaying a DisplayList after modifying the displaylist properties
-     *
-     *  @hide */
-    public void repeatLastDraw() {
-    }
-
     private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
         view.mPrivateFlags |= View.PFLAG_DRAWN;
 
@@ -194,7 +197,8 @@
     @Override
     void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
         attachInfo.mIgnoreDirtyState = true;
-        attachInfo.mDrawingTime = SystemClock.uptimeMillis();
+        long frameTimeNanos = mChoreographer.getFrameTimeNanos();
+        attachInfo.mDrawingTime = frameTimeNanos / NANOS_PER_MS;
 
         updateRootDisplayList(view, callbacks);
 
@@ -203,7 +207,11 @@
         if (dirty == null) {
             dirty = NULL_RECT;
         }
-        nSyncAndDrawFrame(mNativeProxy, dirty.left, dirty.top, dirty.right, dirty.bottom);
+        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
+                dirty.left, dirty.top, dirty.right, dirty.bottom);
+        if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
+            attachInfo.mViewRootImpl.invalidate();
+        }
     }
 
     @Override
@@ -297,13 +305,15 @@
     private static native long nCreateProxy(boolean translucent, long rootRenderNode);
     private static native void nDeleteProxy(long nativeProxy);
 
+    private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos);
+
     private static native boolean nInitialize(long nativeProxy, Surface window);
     private static native void nUpdateSurface(long nativeProxy, Surface window);
     private static native void nPauseSurface(long nativeProxy, Surface window);
     private static native void nSetup(long nativeProxy, int width, int height);
     private static native void nSetDisplayListData(long nativeProxy, long displayList,
             long newData);
-    private static native void nSyncAndDrawFrame(long nativeProxy,
+    private static native int nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos,
             int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
     private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
     private static native void nDestroyCanvasAndSurface(long nativeProxy);
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 20ef429..275389d 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -702,8 +702,9 @@
      *
      * @return how long a user needs to press the relevant key to bring up
      *   the global actions dialog.
-     * @deprecated use getDeviceGlobalActionKeyTimeout
+     * @deprecated
      */
+    @Deprecated
     public static long getGlobalActionKeyTimeout() {
         return GLOBAL_ACTIONS_KEY_TIMEOUT;
     }
@@ -714,6 +715,7 @@
      *
      * @return how long a user needs to press the relevant key to bring up
      *   the global actions dialog.
+     * @hide
      */
     public long getDeviceGlobalActionKeyTimeout() {
         return mGlobalActionsKeyTimeout;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 3fac883..f4cd5fc 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3380,7 +3380,9 @@
                                 mScrollOffset)) {
                             mMotionCorrection -= mScrollOffset[1];
                             lastYCorrection -= mScrollOffset[1];
-                            vtev.offsetLocation(0, mScrollOffset[1]);
+                            if (vtev != null) {
+                                vtev.offsetLocation(0, mScrollOffset[1]);
+                            }
                         } else {
                             overScrollBy(0, overscroll, 0, mScrollY, 0, 0,
                                     0, mOverscrollDistance, true);
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index e4575e5..51759c5 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -649,7 +649,8 @@
     private class OverflowPopup extends MenuPopupHelper {
         public OverflowPopup(Context context, MenuBuilder menu, View anchorView,
                 boolean overflowOnly) {
-            super(context, menu, anchorView, overflowOnly);
+            super(context, menu, anchorView, overflowOnly,
+                    com.android.internal.R.attr.actionOverflowMenuStyle);
             setGravity(Gravity.END);
             setCallback(mPopupPresenterCallback);
         }
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 10ec105..f91865b 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -622,8 +622,8 @@
             // only set this if the dropdown is not always visible
             mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
             mPopup.setTouchInterceptor(mTouchInterceptor);
-            mPopup.showAsDropDown(getAnchorView(),
-                    mDropDownHorizontalOffset, mDropDownVerticalOffset, mDropDownGravity);
+            mPopup.showAsDropDown(getAnchorView(), mDropDownHorizontalOffset,
+                    mDropDownVerticalOffset, mDropDownGravity);
             mDropDownList.setSelection(ListView.INVALID_POSITION);
             
             if (!mModal || mDropDownList.isInTouchMode()) {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 6e71a5c..01632ae 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -18,6 +18,7 @@
 
 import com.android.internal.R;
 
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -116,6 +117,10 @@
     private Drawable mAboveAnchorBackgroundDrawable;
     private Drawable mBelowAnchorBackgroundDrawable;
 
+    // Temporary animation centers. Should be moved into window params?
+    private int mAnchorRelativeX;
+    private int mAnchorRelativeY;
+
     private boolean mAboveAnchor;
     private int mWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
     
@@ -129,12 +134,14 @@
     };
 
     private WeakReference<View> mAnchor;
-    private OnScrollChangedListener mOnScrollChangedListener =
+
+    private final OnScrollChangedListener mOnScrollChangedListener =
         new OnScrollChangedListener() {
+            @Override
             public void onScrollChanged() {
-                View anchor = mAnchor != null ? mAnchor.get() : null;
+                final View anchor = mAnchor != null ? mAnchor.get() : null;
                 if (anchor != null && mPopupView != null) {
-                    WindowManager.LayoutParams p = (WindowManager.LayoutParams)
+                    final WindowManager.LayoutParams p = (WindowManager.LayoutParams)
                             mPopupView.getLayoutParams();
 
                     updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
@@ -143,7 +150,9 @@
                 }
             }
         };
+
     private int mAnchorXoff, mAnchorYoff, mAnchoredGravity;
+    private boolean mOverlapAnchor;
 
     private boolean mPopupViewInitialLayoutDirectionInherited;
 
@@ -187,6 +196,7 @@
                 attrs, com.android.internal.R.styleable.PopupWindow, defStyleAttr, defStyleRes);
 
         mBackground = a.getDrawable(R.styleable.PopupWindow_popupBackground);
+        mOverlapAnchor = a.getBoolean(R.styleable.PopupWindow_overlapAnchor, false);
 
         final int animStyle = a.getResourceId(R.styleable.PopupWindow_popupAnimationStyle, -1);
         mAnimationStyle = animStyle == com.android.internal.R.style.Animation_PopupWindow ? -1 :
@@ -934,9 +944,9 @@
                 // do the job.
                 if (mAboveAnchorBackgroundDrawable != null) {
                     if (mAboveAnchor) {
-                        mPopupView.setBackgroundDrawable(mAboveAnchorBackgroundDrawable);
+                        mPopupView.setBackground(mAboveAnchorBackgroundDrawable);
                     } else {
-                        mPopupView.setBackgroundDrawable(mBelowAnchorBackgroundDrawable);
+                        mPopupView.setBackground(mBelowAnchorBackgroundDrawable);
                     }
                 } else {
                     mPopupView.refreshDrawableState();
@@ -1114,36 +1124,43 @@
         }
         return mAnimationStyle;
     }
-    
+
     /**
-     * <p>Positions the popup window on screen. When the popup window is too
-     * tall to fit under the anchor, a parent scroll view is seeked and scrolled
-     * up to reclaim space. If scrolling is not possible or not enough, the
-     * popup window gets moved on top of the anchor.</p>
-     *
-     * <p>The height must have been set on the layout parameters prior to
-     * calling this method.</p>
-     *
+     * Positions the popup window on screen. When the popup window is too tall
+     * to fit under the anchor, a parent scroll view is seeked and scrolled up
+     * to reclaim space. If scrolling is not possible or not enough, the popup
+     * window gets moved on top of the anchor.
+     * <p>
+     * The height must have been set on the layout parameters prior to calling
+     * this method.
+     * 
      * @param anchor the view on which the popup window must be anchored
      * @param p the layout parameters used to display the drop down
-     *
+     * @param xoff horizontal offset used to adjust for background padding
+     * @param yoff vertical offset used to adjust for background padding
+     * @param gravity horizontal gravity specifying popup alignment
      * @return true if the popup is translated upwards to fit on screen
      */
-    private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
-            int xoff, int yoff, int gravity) {
-
+    private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p, int xoff,
+            int yoff, int gravity) {
         final int anchorHeight = anchor.getHeight();
+        final int anchorWidth = anchor.getWidth();
+        if (mOverlapAnchor) {
+            yoff -= anchorHeight;
+        }
+
         anchor.getLocationInWindow(mDrawingLocation);
         p.x = mDrawingLocation[0] + xoff;
         p.y = mDrawingLocation[1] + anchorHeight + yoff;
 
-        final int hgrav = Gravity.getAbsoluteGravity(gravity, anchor.getLayoutDirection()) &
-                Gravity.HORIZONTAL_GRAVITY_MASK;
+        final int hgrav = Gravity.getAbsoluteGravity(gravity, anchor.getLayoutDirection())
+                & Gravity.HORIZONTAL_GRAVITY_MASK;
         if (hgrav == Gravity.RIGHT) {
-            // Flip the location to align the right sides of the popup and anchor instead of left
-            p.x -= mPopupWidth - anchor.getWidth();
+            // Flip the location to align the right sides of the popup and
+            // anchor instead of left.
+            p.x -= mPopupWidth - anchorWidth;
         }
-        
+
         boolean onTop = false;
 
         p.gravity = Gravity.LEFT | Gravity.TOP;
@@ -1152,60 +1169,58 @@
         final Rect displayFrame = new Rect();
         anchor.getWindowVisibleDisplayFrame(displayFrame);
 
-        int screenY = mScreenLocation[1] + anchorHeight + yoff;
-        
+        final int screenY = mScreenLocation[1] + anchorHeight + yoff;
         final View root = anchor.getRootView();
-        if (screenY + mPopupHeight > displayFrame.bottom ||
-                p.x + mPopupWidth - root.getWidth() > 0) {
-            // if the drop down disappears at the bottom of the screen. we try to
-            // scroll a parent scrollview or move the drop down back up on top of
-            // the edit box
+        if (screenY + mPopupHeight > displayFrame.bottom
+                || p.x + mPopupWidth - root.getWidth() > 0) {
+            // If the drop down disappears at the bottom of the screen, we try
+            // to scroll a parent scrollview or move the drop down back up on
+            // top of the edit box.
             if (mAllowScrollingAnchorParent) {
-                int scrollX = anchor.getScrollX();
-                int scrollY = anchor.getScrollY();
-                Rect r = new Rect(scrollX, scrollY,  scrollX + mPopupWidth + xoff,
-                        scrollY + mPopupHeight + anchor.getHeight() + yoff);
+                final int scrollX = anchor.getScrollX();
+                final int scrollY = anchor.getScrollY();
+                final Rect r = new Rect(scrollX, scrollY, scrollX + mPopupWidth + xoff,
+                        scrollY + mPopupHeight + anchorHeight + yoff);
                 anchor.requestRectangleOnScreen(r, true);
             }
 
-            // now we re-evaluate the space available, and decide from that
+            // Now we re-evaluate the space available, and decide from that
             // whether the pop-up will go above or below the anchor.
             anchor.getLocationInWindow(mDrawingLocation);
             p.x = mDrawingLocation[0] + xoff;
-            p.y = mDrawingLocation[1] + anchor.getHeight() + yoff;
+            p.y = mDrawingLocation[1] + anchorHeight + yoff;
 
-            // Preserve the gravity adjustment
+            // Preserve the gravity adjustment.
             if (hgrav == Gravity.RIGHT) {
-                p.x -= mPopupWidth - anchor.getWidth();
+                p.x -= mPopupWidth - anchorWidth;
             }
-            
-            // determine whether there is more space above or below the anchor
+
+            // Determine whether there is more space above or below the anchor.
             anchor.getLocationOnScreen(mScreenLocation);
-            
-            onTop = (displayFrame.bottom - mScreenLocation[1] - anchor.getHeight() - yoff) <
+            onTop = (displayFrame.bottom - mScreenLocation[1] - anchorHeight - yoff) <
                     (mScreenLocation[1] - yoff - displayFrame.top);
             if (onTop) {
                 p.gravity = Gravity.LEFT | Gravity.BOTTOM;
                 p.y = root.getHeight() - mDrawingLocation[1] + yoff;
             } else {
-                p.y = mDrawingLocation[1] + anchor.getHeight() + yoff;
+                p.y = mDrawingLocation[1] + anchorHeight + yoff;
             }
         }
 
         if (mClipToScreen) {
             final int displayFrameWidth = displayFrame.right - displayFrame.left;
-
-            int right = p.x + p.width;
+            final int right = p.x + p.width;
             if (right > displayFrameWidth) {
                 p.x -= right - displayFrameWidth;
             }
+
             if (p.x < displayFrame.left) {
                 p.x = displayFrame.left;
                 p.width = Math.min(p.width, displayFrameWidth);
             }
 
             if (onTop) {
-                int popupTop = mScreenLocation[1] + yoff - mPopupHeight;
+                final int popupTop = mScreenLocation[1] + yoff - mPopupHeight;
                 if (popupTop < 0) {
                     p.y += popupTop;
                 }
@@ -1215,7 +1230,11 @@
         }
 
         p.gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
-        
+
+        // Compute the position of the anchor relative to the popup.
+        mAnchorRelativeX = mDrawingLocation[0] - p.x + anchorHeight / 2;
+        mAnchorRelativeY = mDrawingLocation[1] - p.y + anchorWidth / 2;
+
         return onTop;
     }
     
@@ -1503,7 +1522,8 @@
         }
 
         WeakReference<View> oldAnchor = mAnchor;
-        final boolean needsUpdate = updateLocation && (mAnchorXoff != xoff || mAnchorYoff != yoff);
+        final boolean needsUpdate = updateLocation
+                && (mAnchorXoff != xoff || mAnchorYoff != yoff);
         if (oldAnchor == null || oldAnchor.get() != anchor || (needsUpdate && !mIsDropdown)) {
             registerForScrollChanged(anchor, xoff, yoff, gravity);
         } else if (needsUpdate) {
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 3219ddd..98e35dd 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -24,8 +24,9 @@
 import android.service.voice.IVoiceInteractionSession;
 
 interface IVoiceInteractionManagerService {
-    void startVoiceActivity(in Intent intent, String resolvedType, IVoiceInteractionService service,
-            in Bundle sessionArgs);
-    int deliverNewSession(IBinder token, IVoiceInteractionSession session,
+    void startSession(IVoiceInteractionService service, in Bundle sessionArgs);
+    boolean deliverNewSession(IBinder token, IVoiceInteractionSession session,
             IVoiceInteractor interactor);
+    int startVoiceActivity(IBinder token, in Intent intent, String resolvedType);
+    void finish(IBinder token);
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 6428e15..caa6b98 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -42,7 +42,7 @@
             out int[] switches, out List<IBinder> binders);
     void onPanelRevealed();
     void onPanelHidden();
-    void onNotificationClick(String pkg, String tag, int id, int userId);
+    void onNotificationClick(String key);
     void onNotificationError(String pkg, String tag, int id,
             int uid, int initialPid, String message, int userId);
     void onClearAllNotifications(int userId);
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index d664058..5a12893 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -53,6 +53,7 @@
     private final MenuAdapter mAdapter;
     private final boolean mOverflowOnly;
     private final int mPopupMaxWidth;
+    private final int mPopupStyleAttr;
 
     private View mAnchorView;
     private ListPopupWindow mPopup;
@@ -72,20 +73,21 @@
     private int mDropDownGravity = Gravity.NO_GRAVITY;
 
     public MenuPopupHelper(Context context, MenuBuilder menu) {
-        this(context, menu, null, false);
+        this(context, menu, null, false, com.android.internal.R.attr.popupMenuStyle);
     }
 
     public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView) {
-        this(context, menu, anchorView, false);
+        this(context, menu, anchorView, false, com.android.internal.R.attr.popupMenuStyle);
     }
 
-    public MenuPopupHelper(Context context, MenuBuilder menu,
-            View anchorView, boolean overflowOnly) {
+    public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView,
+            boolean overflowOnly, int popupStyleAttr) {
         mContext = context;
         mInflater = LayoutInflater.from(context);
         mMenu = menu;
         mAdapter = new MenuAdapter(mMenu);
         mOverflowOnly = overflowOnly;
+        mPopupStyleAttr = popupStyleAttr;
 
         final Resources res = context.getResources();
         mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
@@ -119,7 +121,7 @@
     }
 
     public boolean tryShow() {
-        mPopup = new ListPopupWindow(mContext, null, com.android.internal.R.attr.popupMenuStyle);
+        mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr);
         mPopup.setOnDismissListener(this);
         mPopup.setOnItemClickListener(this);
         mPopup.setAdapter(mAdapter);
@@ -272,7 +274,7 @@
     @Override
     public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
         if (subMenu.hasVisibleItems()) {
-            MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView, false);
+            MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView);
             subPopup.setCallback(mPresenterCallback);
 
             boolean preserveIconSpacing = false;
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 957f95c..05a99a3 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -18,8 +18,12 @@
 // #define LOG_NDEBUG 0
 // #define LOG_NNDEBUG 0
 #define LOG_TAG "CameraMetadata-JNI"
+#include <utils/Errors.h>
 #include <utils/Log.h>
 #include <utils/RefBase.h>
+#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
 #include <string.h>
 
 #include "jni.h"
@@ -483,12 +487,20 @@
 
     ALOGV("%s (key = '%s')", __FUNCTION__, key);
 
+    sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
+
+    SortedVector<String8> vendorSections = vTags->getAllSectionNames();
+    size_t vendorSectionCount = vendorSections.size();
+
     // First, find the section by the longest string match
     const char *section = NULL;
     size_t sectionIndex = 0;
     size_t sectionLength = 0;
-    for (size_t i = 0; i < ANDROID_SECTION_COUNT; ++i) {
-        const char *str = camera_metadata_section_names[i];
+    size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount;
+    for (size_t i = 0; i < totalSectionCount; ++i) {
+
+        const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] :
+                vendorSections[i - ANDROID_SECTION_COUNT].string();
         ALOGVV("%s: Trying to match against section '%s'",
                __FUNCTION__, str);
         if (strstr(key, str) == key) { // key begins with the section name
@@ -502,12 +514,11 @@
                 sectionIndex = i;
                 sectionLength = strLength;
 
-                ALOGVV("%s: Found new best section (idx %d)", __FUNCTION__, sectionIndex);
+                ALOGVV("%s: Found new best section (%s)", __FUNCTION__, section);
             }
         }
     }
 
-    // TODO: vendor ext
     // TODO: Make above get_camera_metadata_section_from_name ?
 
     if (section == NULL) {
@@ -524,33 +535,47 @@
     if (sectionLength + 1 >= keyLength) {
         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
                              "Key length too short for key '%s')", key);
+        return 0;
     }
 
     // Match rest of name against the tag names in that section only
-    uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
-    tagBegin = camera_metadata_section_bounds[sectionIndex][0];
-    tagEnd = camera_metadata_section_bounds[sectionIndex][1];
+    uint32_t tag = 0;
+    if (sectionIndex < ANDROID_SECTION_COUNT) {
+        // Match built-in tags (typically android.*)
+        uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
+        tagBegin = camera_metadata_section_bounds[sectionIndex][0];
+        tagEnd = camera_metadata_section_bounds[sectionIndex][1];
 
-    uint32_t tag;
-    for (tag = tagBegin; tag < tagEnd; ++tag) {
-        const char *tagName = get_camera_metadata_tag_name(tag);
+        for (tag = tagBegin; tag < tagEnd; ++tag) {
+            const char *tagName = get_camera_metadata_tag_name(tag);
 
-        if (strcmp(keyTagName, tagName) == 0) {
-            ALOGV("%s: Found matched tag '%s' (%d)",
-                  __FUNCTION__, tagName, tag);
-            break;
+            if (strcmp(keyTagName, tagName) == 0) {
+                ALOGV("%s: Found matched tag '%s' (%d)",
+                      __FUNCTION__, tagName, tag);
+                break;
+            }
+        }
+
+        if (tag == tagEnd) {
+            jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+                                 "Could not find tag name for key '%s')", key);
+            return 0;
+        }
+    } else {
+        // Match vendor tags (typically com.*)
+        const String8 sectionName(section);
+        const String8 tagName(keyTagName);
+
+        status_t res = OK;
+        if ((res = vTags->lookupTag(tagName, sectionName, &tag)) != OK) {
+            jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+                    "%s: No vendor tag matches key '%s'", __FUNCTION__, key);
+            return 0;
         }
     }
 
-    // TODO: vendor ext
     // TODO: Make above get_camera_metadata_tag_from_name ?
 
-    if (tag == tagEnd) {
-        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
-                             "Could not find tag name for key '%s')", key);
-        return 0;
-    }
-
     return tag;
 }
 
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 564c9a6..cd0ed8c 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -152,6 +152,12 @@
     delete proxy;
 }
 
+static void android_view_ThreadedRenderer_setFrameInterval(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jlong frameIntervalNanos) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    proxy->setFrameInterval(frameIntervalNanos);
+}
+
 static jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jobject jsurface) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -185,11 +191,11 @@
     proxy->setup(width, height);
 }
 
-static void android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jint dirtyLeft, jint dirtyTop,
+static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jlong frameTimeNanos, jint dirtyLeft, jint dirtyTop,
         jint dirtyRight, jint dirtyBottom) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    proxy->syncAndDrawFrame(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
+    return proxy->syncAndDrawFrame(frameTimeNanos, dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
 }
 
 static void android_view_ThreadedRenderer_destroyCanvasAndSurface(JNIEnv* env, jobject clazz,
@@ -261,11 +267,12 @@
     { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
     { "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
     { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
+    { "nSetFrameInterval", "(JJ)V", (void*) android_view_ThreadedRenderer_setFrameInterval },
     { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
     { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
     { "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface },
     { "nSetup", "(JII)V", (void*) android_view_ThreadedRenderer_setup },
-    { "nSyncAndDrawFrame", "(JIIII)V", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
+    { "nSyncAndDrawFrame", "(JJIIII)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
     { "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface },
     { "nInvokeFunctor", "(JJZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
     { "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext },
diff --git a/core/res/res/anim/popup_enter_quantum.xml b/core/res/res/anim/popup_enter_quantum.xml
new file mode 100644
index 0000000..79de26b
--- /dev/null
+++ b/core/res/res/anim/popup_enter_quantum.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shareInterpolator="false" >
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+           android:interpolator="@interpolator/decelerate_cubic"
+           android:duration="@android:integer/config_activityShortDur" />
+</set>
diff --git a/core/res/res/anim/popup_exit_quantum.xml b/core/res/res/anim/popup_exit_quantum.xml
new file mode 100644
index 0000000..7d7d5c5
--- /dev/null
+++ b/core/res/res/anim/popup_exit_quantum.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shareInterpolator="false" >
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+           android:interpolator="@interpolator/decelerate_cubic"
+           android:duration="@android:integer/config_activityShortDur"/>
+</set>
diff --git a/core/res/res/drawable/popup_background_quantum.xml b/core/res/res/drawable/popup_background_quantum.xml
new file mode 100644
index 0000000..7e5b003
--- /dev/null
+++ b/core/res/res/drawable/popup_background_quantum.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+
+    <corners
+        android:radius="2dp" />
+    <solid
+        android:color="?attr/colorBackground" />
+
+</shape>
diff --git a/core/res/res/layout/voice_interaction_session.xml b/core/res/res/layout/voice_interaction_session.xml
new file mode 100644
index 0000000..48b6579
--- /dev/null
+++ b/core/res/res/layout/voice_interaction_session.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/layout/alert_dialog.xml
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+</FrameLayout>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 305ba28..f01f10e 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -348,43 +348,4 @@
         <item>中文 (繁體)</item>
     </string-array>
 
-    <!-- Used by callers to Resources.selectSystemTheme(). Defines the minimum
-         targetSdkVersion required for the theme style at a given index.
-         NOTE: Must be sorted in ascending order. -->
-    <integer-array name="system_theme_sdks">
-        <item>0</item>
-        <item>11</item>
-        <item>14</item>
-        <item>21</item>
-    </integer-array>
-
-    <!-- Used by Resources.selectDefaultTheme(). Defines the default theme style
-         for the targetSdkVersion at a given index (see system_theme_sdks).
-         NOTE: Must match number of entries in system_theme_sdks. -->
-    <array name="system_theme_styles">
-        <item>@style/Theme</item>
-        <item>@style/Theme.Holo</item>
-        <item>@style/Theme.DeviceDefault</item>
-        <item>@style/Theme.DeviceDefault.Light.DarkActionBar</item>
-    </array>
-
-    <!-- Used by ContextImpl for notifications. Defines the default dialog theme
-         style for the targetSdkVersion at a given index (see system_theme_sdks).
-         NOTE: Must match number of entries in system_theme_sdks. -->
-    <array name="system_theme_dialog_styles">
-        <item>@style/Theme</item>
-        <item>@style/Theme.Holo.Dialog</item>
-        <item>@style/Theme.DeviceDefault.Dialog</item>
-        <item>@style/Theme.DeviceDefault.Light.Dialog</item>
-    </array>
-
-    <!-- Used by InputMethodService.onCreate(). Defines the default IME theme
-         style for the targetSdkVersion at a given index (see system_theme_sdks).
-         NOTE: Must match number of entries in system_theme_sdks. -->
-    <array name="system_theme_ime_styles">
-        <item>@style/Theme.InputMethod</item>
-        <item>@style/Theme.Holo.InputMethod</item>
-        <item>@style/Theme.DeviceDefault.InputMethod</item>
-        <item>@style/Theme.DeviceDefault.InputMethod</item>
-    </array>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 07db2f7..0326e18 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -721,6 +721,7 @@
         <attr name="actionBarTabBarStyle" format="reference" />
         <attr name="actionBarTabTextStyle" format="reference" />
         <attr name="actionOverflowButtonStyle" format="reference" />
+        <attr name="actionOverflowMenuStyle" format="reference" />
         <!-- Reference to a style for the Action Bar -->
         <attr name="actionBarStyle" format="reference" />
         <!-- Reference to a style for the split Action Bar. This style
@@ -3803,6 +3804,7 @@
     <declare-styleable name="PopupWindow">
         <attr name="popupBackground" format="reference|color" />
         <attr name="popupAnimationStyle" format="reference" />
+        <attr name="overlapAnchor" format="boolean" />
     </declare-styleable>
     <declare-styleable name="ViewAnimator">
         <!-- Identifier for the animation to use when a view is shown. -->
@@ -5810,6 +5812,9 @@
         <attr name="imeExtractExitAnimation" format="reference" />
     </declare-styleable>
 
+    <declare-styleable name="VoiceInteractionSession">
+    </declare-styleable>
+
     <declare-styleable name="KeyboardView">
         <!-- Default KeyboardView style. -->
         <attr name="keyboardViewStyle" format="reference" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index ec73b9f..e88a6ee 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2168,6 +2168,7 @@
   <public type="attr" name="excludeId" />
   <public type="attr" name="excludeClass" />
   <public type="attr" name="hideOnContentScroll" />
+  <public type="attr" name="actionOverflowMenuStyle" />
 
   <public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
 
@@ -2307,6 +2308,7 @@
   <public type="style" name="Widget.Quantum.ListView.DropDown" />
   <public type="style" name="Widget.Quantum.MediaRouteButton" />
   <public type="style" name="Widget.Quantum.PopupMenu" />
+  <public type="style" name="Widget.Quantum.PopupMenu.Overflow" />
   <public type="style" name="Widget.Quantum.PopupWindow" />
   <public type="style" name="Widget.Quantum.ProgressBar" />
   <public type="style" name="Widget.Quantum.ProgressBar.Horizontal" />
@@ -2366,6 +2368,7 @@
   <public type="style" name="Widget.Quantum.Light.ListView.DropDown" />
   <public type="style" name="Widget.Quantum.Light.MediaRouteButton" />
   <public type="style" name="Widget.Quantum.Light.PopupMenu" />
+  <public type="style" name="Widget.Quantum.Light.PopupMenu.Overflow" />
   <public type="style" name="Widget.Quantum.Light.PopupWindow" />
   <public type="style" name="Widget.Quantum.Light.ProgressBar" />
   <public type="style" name="Widget.Quantum.Light.ProgressBar.Horizontal" />
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 37716f7..891265f 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -169,6 +169,12 @@
         <item name="windowExitAnimation">@anim/input_method_exit</item>
     </style>
 
+    <!-- Window animations that are applied to voice interaction overlay windows. -->
+    <style name="Animation.VoiceInteractionSession">
+        <item name="windowEnterAnimation">@anim/input_method_enter</item>
+        <item name="windowExitAnimation">@anim/input_method_exit</item>
+    </style>
+
     <!-- Special optional fancy IM animations. @hide -->
     <style name="Animation.InputMethodFancy">
         <item name="windowEnterAnimation">@anim/input_method_fancy_enter</item>
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index 7679420..01c3017 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -665,7 +665,8 @@
 
     <style name="Widget.Quantum.ListPopupWindow" parent="Widget.ListPopupWindow">
         <item name="dropDownSelector">@drawable/list_selector_quantum</item>
-        <item name="popupBackground">?attr/colorBackground</item>
+        <item name="popupBackground">@drawable/popup_background_quantum</item>
+        <item name="popupAnimationStyle">@style/Animation.Quantum.Popup</item>
         <item name="dropDownVerticalOffset">0dip</item>
         <item name="dropDownHorizontalOffset">0dip</item>
         <item name="dropDownWidth">wrap_content</item>
@@ -673,6 +674,10 @@
 
     <style name="Widget.Quantum.PopupMenu" parent="Widget.Quantum.ListPopupWindow"/>
 
+    <style name="Widget.Quantum.PopupMenu.Overflow">
+        <item name="overlapAnchor">true</item>
+    </style>
+
     <style name="Widget.Quantum.ActionButton" parent="Widget.ActionButton">
         <item name="minWidth">@dimen/action_button_min_width_quantum</item>
         <item name="minHeight">@dimen/action_button_min_height_quantum</item>
@@ -907,17 +912,9 @@
     <style name="Widget.Quantum.Light.QuickContactBadgeSmall.WindowSmall" parent="Widget.Quantum.QuickContactBadgeSmall.WindowSmall"/>
     <style name="Widget.Quantum.Light.QuickContactBadgeSmall.WindowMedium" parent="Widget.Quantum.QuickContactBadgeSmall.WindowMedium"/>
     <style name="Widget.Quantum.Light.QuickContactBadgeSmall.WindowLarge" parent="Widget.Quantum.QuickContactBadgeSmall.WindowLarge"/>
-
-    <style name="Widget.Quantum.Light.ListPopupWindow" parent="Widget.ListPopupWindow">
-        <item name="dropDownSelector">@drawable/list_selector_quantum</item>
-        <item name="popupBackground">?attr/colorBackground</item>
-        <item name="dropDownVerticalOffset">0dip</item>
-        <item name="dropDownHorizontalOffset">0dip</item>
-        <item name="dropDownWidth">wrap_content</item>
-    </style>
-
-    <style name="Widget.Quantum.Light.PopupMenu" parent="Widget.Quantum.Light.ListPopupWindow"/>
-
+    <style name="Widget.Quantum.Light.ListPopupWindow" parent="Widget.Quantum.ListPopupWindow"/>
+    <style name="Widget.Quantum.Light.PopupMenu" parent="Widget.Quantum.ListPopupWindow"/>
+    <style name="Widget.Quantum.Light.PopupMenu.Overflow" parent="Widget.Quantum.PopupMenu.Overflow"/>
     <style name="Widget.Quantum.Light.ActionButton" parent="Widget.Quantum.ActionButton"/>
     <style name="Widget.Quantum.Light.ActionButton.Overflow" parent="Widget.Quantum.ActionButton.Overflow"/>
     <style name="Widget.Quantum.Light.Tab" parent="Widget.Quantum.Tab"/>
@@ -961,7 +958,16 @@
 
     <style name="Animation.Quantum" parent="Animation"/>
     <style name="Animation.Quantum.Activity" parent="Animation.Activity"/>
-    <style name="Animation.Quantum.Dialog" parent="Animation.Dialog"/>
+
+    <style name="Animation.Quantum.Dialog">
+        <item name="windowEnterAnimation">@anim/popup_enter_quantum</item>
+        <item name="windowExitAnimation">@anim/popup_exit_quantum</item>
+    </style>
+
+    <style name="Animation.Quantum.Popup">
+        <item name="windowEnterAnimation">@anim/popup_enter_quantum</item>
+        <item name="windowExitAnimation">@anim/popup_exit_quantum</item>
+    </style>
 
     <!-- Dialog styles -->
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7c6a91a..a8a4b51 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1198,6 +1198,7 @@
   <java-symbol type="layout" name="transient_notification" />
   <java-symbol type="layout" name="volume_adjust" />
   <java-symbol type="layout" name="volume_adjust_item" />
+  <java-symbol type="layout" name="voice_interaction_session" />
   <java-symbol type="layout" name="web_text_view_dropdown" />
   <java-symbol type="layout" name="webview_find" />
   <java-symbol type="layout" name="webview_select_singlechoice" />
@@ -1269,6 +1270,7 @@
   <java-symbol type="style" name="TextAppearance.SlidingTabNormal" />
   <java-symbol type="style" name="Theme.DeviceDefault.Dialog.NoFrame" />
   <java-symbol type="style" name="Theme.IconMenu" />
+  <java-symbol type="style" name="Theme.DeviceDefault.VoiceInteractionSession" />
 
   <java-symbol type="attr" name="mediaRouteButtonStyle" />
   <java-symbol type="attr" name="externalRouteEnabledDrawable" />
@@ -1862,9 +1864,5 @@
   <java-symbol type="id" name="icon_frame" />
   <java-symbol type="style" name="Animation.VolumePanel" />
   <java-symbol type="transition" name="no_transition" />
-  <java-symbol type="array" name="system_theme_sdks" />
-  <java-symbol type="array" name="system_theme_styles" />
-  <java-symbol type="array" name="system_theme_dialog_styles" />
-  <java-symbol type="array" name="system_theme_ime_styles" />
 
 </resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 6f4e7d0..34ef508 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -336,6 +336,7 @@
         <item name="actionDropDownStyle">@android:style/Widget.Spinner.DropDown</item>
         <item name="actionButtonStyle">@android:style/Widget.ActionButton</item>
         <item name="actionOverflowButtonStyle">@android:style/Widget.ActionButton.Overflow</item>
+        <item name="actionOverflowMenuStyle">?android:attr/popupMenuStyle</item>
         <item name="actionModeBackground">@android:drawable/cab_background_top_holo_dark</item>
         <item name="actionModeSplitBackground">@null</item>
         <item name="actionModeCloseDrawable">@android:drawable/ic_menu_close_clear_cancel</item>
@@ -805,6 +806,14 @@
         <item name="android:imeExtractExitAnimation">@android:anim/input_method_extract_exit</item>
     </style>
 
+    <!-- Default theme for voice interaction, which is used by the
+         {@link android.service.voice.VoiceInteractionSession} class.
+         this inherits from Theme.Panel, but sets up appropriate animations
+         and a few custom attributes. -->
+    <style name="Theme.VoiceInteractionSession" parent="Theme.Panel">
+        <item name="android:windowAnimationStyle">@android:style/Animation.VoiceInteractionSession</item>
+    </style>
+
     <!-- Default theme for holo style input methods, which is used by the
          {@link android.inputmethodservice.InputMethodService} class.
          this inherits from Theme.Panel, but sets up IME appropriate animations
@@ -1205,6 +1214,7 @@
         <item name="actionDropDownStyle">@android:style/Widget.Holo.Spinner.DropDown.ActionBar</item>
         <item name="actionButtonStyle">@android:style/Widget.Holo.ActionButton</item>
         <item name="actionOverflowButtonStyle">@android:style/Widget.Holo.ActionButton.Overflow</item>
+        <item name="actionOverflowMenuStyle">?android:attr/popupMenuStyle</item>
         <item name="actionModeBackground">@android:drawable/cab_background_top_holo_dark</item>
         <item name="actionModeSplitBackground">@android:drawable/cab_background_bottom_holo_dark</item>
         <item name="actionModeCloseDrawable">@android:drawable/ic_cab_done_holo_dark</item>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 80c10dd..dbc3d9e 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -299,6 +299,11 @@
          {@link android.inputmethodservice.InputMethodService} class.-->
     <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Quantum.InputMethod"  />
 
+    <!-- DeviceDefault style for input methods, which is used by the
+         {@link android.service.voice.VoiceInteractionSession} class.-->
+    <style name="Theme.DeviceDefault.VoiceInteractionSession" parent="Theme.Quantum.VoiceInteractionSession" >
+
+    </style>
     <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Quantum.Dialog.Alert">
         <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
     </style>
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index c0bd18b..39c8beb 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -291,6 +291,7 @@
         <item name="actionDropDownStyle">@style/Widget.Quantum.Spinner.DropDown.ActionBar</item>
         <item name="actionButtonStyle">@style/Widget.Quantum.ActionButton</item>
         <item name="actionOverflowButtonStyle">@style/Widget.Quantum.ActionButton.Overflow</item>
+        <item name="actionOverflowMenuStyle">@android:style/Widget.Quantum.PopupMenu.Overflow</item>
         <item name="actionModeBackground">?attr/colorPrimaryDark</item>
         <item name="actionModeSplitBackground">?attr/colorPrimaryDark</item>
         <item name="actionModeCloseDrawable">@drawable/ic_cab_done_quantum</item>
@@ -636,6 +637,7 @@
         <item name="actionDropDownStyle">@style/Widget.Quantum.Light.Spinner.DropDown.ActionBar</item>
         <item name="actionButtonStyle">@style/Widget.Quantum.Light.ActionButton</item>
         <item name="actionOverflowButtonStyle">@style/Widget.Quantum.Light.ActionButton.Overflow</item>
+        <item name="actionOverflowMenuStyle">@android:style/Widget.Quantum.Light.PopupMenu.Overflow</item>
         <item name="actionModeBackground">@drawable/cab_background_top_holo_light</item>
         <item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_light</item>
         <item name="actionModeCloseDrawable">@drawable/ic_cab_done_quantum</item>
@@ -853,6 +855,14 @@
         <item name="imeExtractExitAnimation">@anim/input_method_extract_exit</item>
     </style>
 
+    <!-- Default theme for quantum style voice interaction, which is used by the
+         {@link android.service.voice.VoiceInteractionSession} class.
+         this inherits from Theme.Panel, but sets up appropriate animations
+         and a few custom attributes. -->
+    <style name="Theme.Quantum.VoiceInteractionSession" parent="Theme.Quantum.Light.Panel">
+        <item name="android:windowAnimationStyle">@android:style/Animation.VoiceInteractionSession</item>
+    </style>
+
     <!-- Theme for the search input bar. -->
 
     <style name="Theme.Quantum.SearchBar" parent="Theme.Quantum.Panel">
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index d324439..eb0cac8 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -59,7 +59,8 @@
 		renderthread/DrawFrameTask.cpp \
 		renderthread/RenderProxy.cpp \
 		renderthread/RenderTask.cpp \
-		renderthread/RenderThread.cpp
+		renderthread/RenderThread.cpp \
+		renderthread/TimeLord.cpp
 
 	intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
 
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index b52003c..647c281 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -737,30 +737,34 @@
             // a null path is OK because there are no custom kernels used
             // hence nothing gets cached by RS
             if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
+                mRs.clear();
                 ALOGE("blur RS failed to init");
+            } else {
+                mRsElement = RSC::Element::A_8(mRs);
+                mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
             }
-
-            mRsElement = RSC::Element::A_8(mRs);
-            mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
         }
+        if (mRs != 0) {
+            RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
+            RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
+                    RS_ALLOCATION_MIPMAP_NONE,
+                    RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
+                    *image);
+            RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
+                    RS_ALLOCATION_MIPMAP_NONE,
+                    RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
+                    outImage);
 
-        RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
-        RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
-                RS_ALLOCATION_MIPMAP_NONE, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
-                *image);
-        RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
-                RS_ALLOCATION_MIPMAP_NONE, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
-                outImage);
+            mRsScript->setRadius(radius);
+            mRsScript->setInput(ain);
+            mRsScript->forEach(aout);
 
-        mRsScript->setRadius(radius);
-        mRsScript->setInput(ain);
-        mRsScript->forEach(aout);
+            // replace the original image's pointer, avoiding a copy back to the original buffer
+            free(*image);
+            *image = outImage;
 
-        // replace the original image's pointer, avoiding a copy back to the original buffer
-        free(*image);
-        *image = outImage;
-
-        return;
+            return;
+        }
     }
 #endif
 
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 2c29985..9902ff1 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -160,13 +160,13 @@
     newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
     mAnimators.erase(newEnd, mAnimators.end());
     mProperties.updateMatrix();
-    info.hasAnimations |= mAnimators.size();
+    info.out.hasAnimations |= mAnimators.size();
 }
 
 void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
     if (subtree) {
         TextureCache& cache = Caches::getInstance().textureCache;
-        info.hasFunctors |= subtree->functorCount;
+        info.out.hasFunctors |= subtree->functorCount;
         // TODO: Fix ownedBitmapResources to not require disabling prepareTextures
         // and thus falling out of async drawing path.
         if (subtree->ownedBitmapResources.size()) {
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index a383fbf..fc5994c 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -34,25 +34,33 @@
 struct TreeInfo {
     // The defaults here should be safe for everyone but DrawFrameTask to use as-is.
     TreeInfo()
-            : hasFunctors(false)
-            , prepareTextures(false)
-            , performStagingPush(true)
-            , frameTimeMs(0)
-            , evaluateAnimations(false)
-            , hasAnimations(false)
-            , animationHook(0)
+        : frameTimeMs(0)
+        , animationHook(NULL)
+        , prepareTextures(false)
+        , performStagingPush(true)
+        , evaluateAnimations(false)
     {}
 
-    bool hasFunctors;
+    nsecs_t frameTimeMs;
+    AnimationHook* animationHook;
     bool prepareTextures;
     bool performStagingPush;
-
-    // Animations
-    nsecs_t frameTimeMs;
     bool evaluateAnimations;
-    // This is only updated if evaluateAnimations is true
-    bool hasAnimations;
-    AnimationHook* animationHook;
+
+    struct Out {
+        Out()
+            : hasFunctors(false)
+            , hasAnimations(false)
+            , requiresUiRedraw(false)
+        {}
+        bool hasFunctors;
+        // This is only updated if evaluateAnimations is true
+        bool hasAnimations;
+        // This is set to true if there is an animation that RenderThread cannot
+        // animate itself, such as if hasFunctors is true
+        // This is only set if hasAnimations is true
+        bool requiresUiRedraw;
+    } out;
 
     // TODO: Damage calculations
 };
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 63f4b95..fc3548c 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -391,10 +391,20 @@
     mHaveNewSurface |= mGlobalContext->makeCurrent(mEglSurface);
 }
 
+void CanvasContext::prepareDraw(const Vector<DeferredLayerUpdater*>* layerUpdaters,
+        TreeInfo& info) {
+    LOG_ALWAYS_FATAL_IF(!mCanvas, "Cannot prepareDraw without a canvas!");
+    makeCurrent();
+
+    processLayerUpdates(layerUpdaters, info);
+    if (info.out.hasAnimations) {
+        // TODO: Uh... crap?
+    }
+    prepareTree(info);
+}
+
 void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters,
         TreeInfo& info) {
-    LOG_ALWAYS_FATAL_IF(!mCanvas, "Cannot process layer updates without a canvas!");
-    makeCurrent();
     for (size_t i = 0; i < layerUpdaters->size(); i++) {
         DeferredLayerUpdater* update = layerUpdaters->itemAt(i);
         bool success = update->apply(info);
@@ -406,11 +416,19 @@
 }
 
 void CanvasContext::prepareTree(TreeInfo& info) {
+    mRenderThread.removeFrameCallback(this);
+
+    info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
     mRootRenderNode->prepareTree(info);
 
-    if (info.hasAnimations && !info.hasFunctors) {
-        // TODO: Functors
-        mRenderThread.postFrameCallback(this);
+    if (info.out.hasAnimations) {
+        if (info.out.hasFunctors) {
+            info.out.requiresUiRedraw = true;
+        } else if (!info.out.requiresUiRedraw) {
+            // If animationsNeedsRedraw is set don't bother posting for an RT anim
+            // as we will just end up fighting the UI thread.
+            mRenderThread.postFrameCallback(this);
+        }
     }
 }
 
@@ -449,12 +467,11 @@
 }
 
 // Called by choreographer to do an RT-driven animation
-void CanvasContext::doFrame(nsecs_t frameTimeNanos) {
+void CanvasContext::doFrame() {
     ATRACE_CALL();
 
     TreeInfo info;
     info.evaluateAnimations = true;
-    info.frameTimeMs = nanoseconds_to_milliseconds(frameTimeNanos);
     info.performStagingPush = false;
     info.prepareTextures = false;
 
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 0873ad4..a95e27a 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -53,13 +53,12 @@
     void pauseSurface(EGLNativeWindowType window);
     void setup(int width, int height);
     void makeCurrent();
-    void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
-    void prepareTree(TreeInfo& info);
+    void prepareDraw(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
     void draw(Rect* dirty);
     void destroyCanvasAndSurface();
 
     // IFrameCallback, Chroreographer-driven frame callback entry point
-    virtual void doFrame(nsecs_t frameTimeNanos);
+    virtual void doFrame();
 
     bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
 
@@ -71,6 +70,9 @@
     Layer* createTextureLayer();
 
 private:
+    void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
+    void prepareTree(TreeInfo& info);
+
     void setSurface(EGLNativeWindowType window);
     void swapBuffers();
     void requireSurface();
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 45f5cb0..3b8786c 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -30,13 +30,18 @@
 namespace uirenderer {
 namespace renderthread {
 
-DrawFrameTask::DrawFrameTask() : mContext(0) {
+DrawFrameTask::DrawFrameTask()
+        : mRenderThread(NULL)
+        , mContext(NULL)
+        , mFrameTimeNanos(0)
+        , mSyncResult(kSync_OK) {
 }
 
 DrawFrameTask::~DrawFrameTask() {
 }
 
-void DrawFrameTask::setContext(CanvasContext* context) {
+void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context) {
+    mRenderThread = thread;
     mContext = context;
 }
 
@@ -59,18 +64,23 @@
     mDirty.set(left, top, right, bottom);
 }
 
-void DrawFrameTask::drawFrame(RenderThread* renderThread) {
+int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos) {
     LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
 
-    postAndWait(renderThread);
+    mSyncResult = kSync_OK;
+    mFrameTimeNanos = frameTimeNanos;
+    postAndWait();
 
     // Reset the single-frame data
+    mFrameTimeNanos = 0;
     mDirty.setEmpty();
+
+    return mSyncResult;
 }
 
-void DrawFrameTask::postAndWait(RenderThread* renderThread) {
+void DrawFrameTask::postAndWait() {
     AutoMutex _lock(mLock);
-    renderThread->queue(this);
+    mRenderThread->queue(this);
     mSignal.wait(mLock);
 }
 
@@ -99,25 +109,25 @@
     info.prepareTextures = true;
     info.performStagingPush = true;
     info.evaluateAnimations = true;
-    // TODO: Get this from Choreographer
-    nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC);
-    info.frameTimeMs = nanoseconds_to_milliseconds(frameTimeNs);
 }
 
 bool DrawFrameTask::syncFrameState() {
     ATRACE_CALL();
+    mRenderThread->timeLord().vsyncReceived(mFrameTimeNanos);
     mContext->makeCurrent();
     Caches::getInstance().textureCache.resetMarkInUse();
     TreeInfo info;
     initTreeInfo(info);
-    mContext->processLayerUpdates(&mLayers, info);
-    mContext->prepareTree(info);
-    if (info.hasAnimations) {
+    mContext->prepareDraw(&mLayers, info);
+    if (info.out.hasAnimations) {
         // TODO: dirty calculations, for now just do a full-screen inval
         mDirty.setEmpty();
+        if (info.out.requiresUiRedraw) {
+            mSyncResult |= kSync_UIRedrawRequired;
+        }
     }
     // If prepareTextures is false, we ran out of texture cache space
-    return !info.hasFunctors && info.prepareTextures;
+    return !info.out.hasFunctors && info.prepareTextures;
 }
 
 void DrawFrameTask::unblockUiThread() {
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index c280868..b9307e1 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -37,6 +37,11 @@
 class CanvasContext;
 class RenderThread;
 
+enum SyncResult {
+    kSync_OK = 0,
+    kSync_UIRedrawRequired = 1 << 1,
+};
+
 /*
  * This is a special Super Task. It is re-used multiple times by RenderProxy,
  * and contains state (such as layer updaters & new DisplayListDatas) that is
@@ -48,30 +53,34 @@
     DrawFrameTask();
     virtual ~DrawFrameTask();
 
-    void setContext(CanvasContext* context);
+    void setContext(RenderThread* thread, CanvasContext* context);
 
     void addLayer(DeferredLayerUpdater* layer);
     void removeLayer(DeferredLayerUpdater* layer);
 
     void setDirty(int left, int top, int right, int bottom);
-    void drawFrame(RenderThread* renderThread);
+    int drawFrame(nsecs_t frameTimeNanos);
 
     virtual void run();
 
 private:
-    void postAndWait(RenderThread* renderThread);
+    void postAndWait();
     bool syncFrameState();
     void unblockUiThread();
 
     Mutex mLock;
     Condition mSignal;
 
+    RenderThread* mRenderThread;
     CanvasContext* mContext;
 
     /*********************************************
      *  Single frame data
      *********************************************/
     Rect mDirty;
+    nsecs_t mFrameTimeNanos;
+
+    int mSyncResult;
 
     /*********************************************
      *  Multi frame data
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 87886e6..31bb61a 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -62,7 +62,7 @@
     args->translucent = translucent;
     args->rootRenderNode = rootRenderNode;
     mContext = (CanvasContext*) postAndWait(task);
-    mDrawFrameTask.setContext(mContext);
+    mDrawFrameTask.setContext(&mRenderThread, mContext);
 }
 
 RenderProxy::~RenderProxy() {
@@ -79,13 +79,25 @@
         SETUP_TASK(destroyContext);
         args->context = mContext;
         mContext = 0;
-        mDrawFrameTask.setContext(0);
+        mDrawFrameTask.setContext(NULL, NULL);
         // This is also a fence as we need to be certain that there are no
         // outstanding mDrawFrame tasks posted before it is destroyed
         postAndWait(task);
     }
 }
 
+CREATE_BRIDGE2(setFrameInterval, RenderThread* thread, nsecs_t frameIntervalNanos) {
+    args->thread->timeLord().setFrameInterval(args->frameIntervalNanos);
+    return NULL;
+}
+
+void RenderProxy::setFrameInterval(nsecs_t frameIntervalNanos) {
+    SETUP_TASK(setFrameInterval);
+    args->thread = &mRenderThread;
+    args->frameIntervalNanos = frameIntervalNanos;
+    post(task);
+}
+
 CREATE_BRIDGE2(initialize, CanvasContext* context, EGLNativeWindowType window) {
     return (void*) args->context->initialize(args->window);
 }
@@ -134,10 +146,10 @@
     post(task);
 }
 
-void RenderProxy::syncAndDrawFrame(
+int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos,
         int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) {
     mDrawFrameTask.setDirty(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
-    mDrawFrameTask.drawFrame(&mRenderThread);
+    return mDrawFrameTask.drawFrame(frameTimeNanos);
 }
 
 CREATE_BRIDGE1(destroyCanvasAndSurface, CanvasContext* context) {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index eab1395..984cc65 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -25,6 +25,7 @@
 #include <utils/Condition.h>
 #include <utils/Functor.h>
 #include <utils/Mutex.h>
+#include <utils/Timers.h>
 #include <utils/StrongPointer.h>
 #include <utils/Vector.h>
 
@@ -59,11 +60,13 @@
     ANDROID_API RenderProxy(bool translucent, RenderNode* rootNode);
     ANDROID_API virtual ~RenderProxy();
 
+    ANDROID_API void setFrameInterval(nsecs_t frameIntervalNanos);
+
     ANDROID_API bool initialize(const sp<ANativeWindow>& window);
     ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
     ANDROID_API void pauseSurface(const sp<ANativeWindow>& window);
     ANDROID_API void setup(int width, int height);
-    ANDROID_API void syncAndDrawFrame(
+    ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos,
             int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
     ANDROID_API void destroyCanvasAndSurface();
 
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index e95707a..35a3eab 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -129,8 +129,7 @@
         , mDisplayEventReceiver(0)
         , mVsyncRequested(false)
         , mFrameCallbackTaskPending(false)
-        , mFrameCallbackTask(0)
-        , mFrameTime(0) {
+        , mFrameCallbackTask(0) {
     mFrameCallbackTask = new DispatchFrameCallbacks(this);
     mLooper = new Looper(false);
     run("RenderThread");
@@ -193,7 +192,7 @@
     nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver);
     if (vsyncEvent > 0) {
         mVsyncRequested = false;
-        mFrameTime = vsyncEvent;
+        mTimeLord.vsyncReceived(vsyncEvent);
         if (!mFrameCallbackTaskPending) {
             mFrameCallbackTaskPending = true;
             //queueDelayed(mFrameCallbackTask, DISPATCH_FRAME_CALLBACKS_DELAY);
@@ -209,7 +208,7 @@
     mFrameCallbacks.swap(callbacks);
 
     for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) {
-        (*it)->doFrame(mFrameTime);
+        (*it)->doFrame();
     }
 }
 
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index b93dfd6..215d294 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -28,6 +28,8 @@
 #include <utils/Singleton.h>
 #include <utils/Thread.h>
 
+#include "TimeLord.h"
+
 namespace android {
 class DisplayEventReceiver;
 
@@ -53,7 +55,7 @@
 // Mimics android.view.Choreographer.FrameCallback
 class IFrameCallback {
 public:
-    virtual void doFrame(nsecs_t frameTimeNanos) = 0;
+    virtual void doFrame() = 0;
 
 protected:
     ~IFrameCallback() {}
@@ -71,6 +73,8 @@
     void postFrameCallback(IFrameCallback* callback);
     void removeFrameCallback(IFrameCallback* callback);
 
+    TimeLord& timeLord() { return mTimeLord; }
+
 protected:
     virtual bool threadLoop();
 
@@ -102,7 +106,8 @@
     std::set<IFrameCallback*> mFrameCallbacks;
     bool mFrameCallbackTaskPending;
     DispatchFrameCallbacks* mFrameCallbackTask;
-    nsecs_t mFrameTime;
+
+    TimeLord mTimeLord;
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp
new file mode 100644
index 0000000..758d96e
--- /dev/null
+++ b/libs/hwui/renderthread/TimeLord.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "TimeLord.h"
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+TimeLord::TimeLord()
+        : mFrameIntervalNanos(0)
+        , mFrameTimeNanos(0) {
+}
+
+void TimeLord::vsyncReceived(nsecs_t vsync) {
+    if (vsync > mFrameTimeNanos) {
+        mFrameTimeNanos = vsync;
+    }
+}
+
+nsecs_t TimeLord::frameTimeMs() {
+    // Logic copied from Choreographer.java
+    nsecs_t now = systemTime(CLOCK_MONOTONIC);
+    nsecs_t jitterNanos = now - mFrameTimeNanos;
+    if (jitterNanos >= mFrameIntervalNanos) {
+        nsecs_t lastFrameOffset = jitterNanos % mFrameIntervalNanos;
+        mFrameTimeNanos = now - lastFrameOffset;
+    }
+    return nanoseconds_to_milliseconds(mFrameTimeNanos);
+}
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/TimeLord.h b/libs/hwui/renderthread/TimeLord.h
new file mode 100644
index 0000000..52c6d9e
--- /dev/null
+++ b/libs/hwui/renderthread/TimeLord.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef TIMELORD_H
+#define TIMELORD_H
+
+#include <utils/Timers.h>
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+class RenderThread;
+
+// This class serves as a helper to filter & manage frame times from multiple sources
+// ensuring that time flows linearly and smoothly
+class TimeLord {
+public:
+    void setFrameInterval(nsecs_t intervalNanos) { mFrameIntervalNanos = intervalNanos; }
+    void vsyncReceived(nsecs_t vsync);
+    nsecs_t frameTimeMs();
+
+private:
+    friend class RenderThread;
+
+    TimeLord();
+    ~TimeLord() {}
+
+    nsecs_t mFrameIntervalNanos;
+    nsecs_t mFrameTimeNanos;
+};
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* TIMELORD_H */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index edf54d1..2c7464a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -773,8 +773,8 @@
 
         PendingIntent contentIntent = sbn.getNotification().contentIntent;
         if (contentIntent != null) {
-            final View.OnClickListener listener = makeClicker(contentIntent,
-                    sbn.getPackageName(), sbn.getTag(), sbn.getId(), isHeadsUp, sbn.getUserId());
+            final View.OnClickListener listener = makeClicker(contentIntent, sbn.getKey(),
+                    isHeadsUp);
             row.setOnClickListener(listener);
         } else {
             row.setOnClickListener(null);
@@ -884,27 +884,20 @@
         return true;
     }
 
-    public NotificationClicker makeClicker(PendingIntent intent, String pkg, String tag,
-            int id, boolean forHun, int userId) {
-        return new NotificationClicker(intent, pkg, tag, id, forHun, userId);
+    public NotificationClicker makeClicker(PendingIntent intent, String notificationKey,
+            boolean forHun) {
+        return new NotificationClicker(intent, notificationKey, forHun);
     }
 
     protected class NotificationClicker implements View.OnClickListener {
         private PendingIntent mIntent;
-        private String mPkg;
-        private String mTag;
-        private int mId;
+        private final String mNotificationKey;
         private boolean mIsHeadsUp;
-        private int mUserId;
 
-        public NotificationClicker(PendingIntent intent, String pkg, String tag, int id,
-                boolean forHun, int userId) {
+        public NotificationClicker(PendingIntent intent, String notificationKey, boolean forHun) {
             mIntent = intent;
-            mPkg = pkg;
-            mTag = tag;
-            mId = id;
+            mNotificationKey = notificationKey;
             mIsHeadsUp = forHun;
-            mUserId = userId;
         }
 
         public void onClick(View v) {
@@ -940,7 +933,7 @@
                 if (mIsHeadsUp) {
                     mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
                 }
-                mBarService.onNotificationClick(mPkg, mTag, mId, mUserId);
+                mBarService.onNotificationClick(mNotificationKey);
             } catch (RemoteException ex) {
                 // system process is dead if we're here.
             }
@@ -1344,9 +1337,8 @@
         // update the contentIntent
         final PendingIntent contentIntent = notification.getNotification().contentIntent;
         if (contentIntent != null) {
-            final View.OnClickListener listener = makeClicker(contentIntent,
-                    notification.getPackageName(), notification.getTag(), notification.getId(),
-                    isHeadsUp, notification.getUserId());
+            final View.OnClickListener listener = makeClicker(contentIntent, notification.getKey(),
+                    isHeadsUp);
             entry.row.setOnClickListener(listener);
         } else {
             entry.row.setOnClickListener(null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 554892c..e24ddd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -205,10 +205,12 @@
         } else {
             mContainer.setSystemUiVisibility(vis | View.STATUS_BAR_DISABLE_BACK);
         }
-        if (!(mShowing && !mOccluded) || mBouncer.isShowing()) {
-            mPhoneStatusBar.getNavigationBarView().setVisibility(View.VISIBLE);
-        } else {
-            mPhoneStatusBar.getNavigationBarView().setVisibility(View.GONE);
+        if (mPhoneStatusBar.getNavigationBarView() != null) {
+            if (!(mShowing && !mOccluded) || mBouncer.isShowing()) {
+                mPhoneStatusBar.getNavigationBarView().setVisibility(View.VISIBLE);
+            } else {
+                mPhoneStatusBar.getNavigationBarView().setVisibility(View.GONE);
+            }
         }
         mPhoneStatusBar.setBouncerShowing(mBouncer.isShowing());
     }
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 5083d44..6fab37c2 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -65,6 +65,8 @@
 27501 notification_panel_hidden
 # when notifications are newly displayed on screen, or disappear from screen
 27510 notification_visibility_changed (newlyVisibleKeys|3),(noLongerVisibleKeys|3)
+# when a notification has been clicked
+27520 notification_clicked (key|3)
 
 # ---------------------------
 # Watchdog.java
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 6fc3e77..7ed1cc7 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -1548,7 +1548,8 @@
 
                     mImeSwitcherNotification.setLatestEventInfo(
                             mContext, title, summary, mImeSwitchPendingIntent);
-                    if (mNotificationManager != null) {
+                    if ((mNotificationManager != null)
+                            && !mWindowManagerService.hasNavigationBar()) {
                         if (DEBUG) {
                             Slog.d(TAG, "--- show notification: label =  " + summary);
                         }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index f506eab..7c3f288 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -480,7 +480,7 @@
     void setTask(TaskRecord newTask, ThumbnailHolder newThumbHolder, boolean isRoot) {
         if (task != null && task.removeActivity(this)) {
             if (task != newTask) {
-                task.stack.removeTask(task);
+                task.stack.removeTask(task, false);
             } else {
                 Slog.d(TAG, "!!! REMOVE THIS LOG !!! setTask: nearly removed stack=" +
                         (newTask == null ? null : newTask.stack));
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index d5ab277..ee39b67 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -2841,7 +2841,7 @@
             if (mStackSupervisor.isFrontStack(this) && task == topTask() && task.mOnTopOfHome) {
                 mStackSupervisor.moveHomeToTop();
             }
-            removeTask(task);
+            removeTask(task, false);
         }
         cleanUpActivityServicesLocked(r);
         r.removeUriPermissionsLocked();
@@ -3717,7 +3717,7 @@
         return starting;
     }
 
-    void removeTask(TaskRecord task) {
+    void removeTask(TaskRecord task, boolean moving) {
         mStackSupervisor.endLockTaskModeIfTaskEnding(task);
         mWindowManager.removeTask(task.taskId);
         final ActivityRecord r = mResumedActivity;
@@ -3731,9 +3731,13 @@
             mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;
         }
         mTaskHistory.remove(task);
-        if (task.voiceInteractor != null) {
+        if (!moving && task.voiceSession != null) {
             // This task was a voice interaction, so it should not remain on the
             // recent tasks list.
+            try {
+                task.voiceSession.taskFinished(task.intent, task.taskId);
+            } catch (RemoteException e) {
+            }
             mService.mRecentTasks.remove(task);
         }
 
@@ -3753,7 +3757,7 @@
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             boolean toTop) {
         TaskRecord task = new TaskRecord(taskId, info, intent, voiceSession, voiceInteractor);
-        addTask(task, toTop);
+        addTask(task, toTop, false);
         return task;
     }
 
@@ -3761,13 +3765,19 @@
         return new ArrayList<TaskRecord>(mTaskHistory);
     }
 
-    void addTask(final TaskRecord task, final boolean toTop) {
+    void addTask(final TaskRecord task, final boolean toTop, boolean moving) {
         task.stack = this;
         if (toTop) {
             insertTaskAtTop(task);
         } else {
             mTaskHistory.add(0, task);
         }
+        if (!moving && task.voiceSession != null) {
+            try {
+                task.voiceSession.taskStarted(task.intent, task.taskId);
+            } catch (RemoteException e) {
+            }
+        }
     }
 
     public int getStackId() {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 9107cb6..2e979d2 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2237,8 +2237,8 @@
             Slog.w(TAG, "moveTaskToStack: no stack for id=" + stackId);
             return;
         }
-        task.stack.removeTask(task);
-        stack.addTask(task, toTop);
+        task.stack.removeTask(task, true);
+        stack.addTask(task, toTop, true);
         mWindowManager.addTask(taskId, stackId, toTop);
         resumeTopActivitiesLocked();
     }
@@ -3119,7 +3119,7 @@
                 }
             }
             ActivityInfo aInfo = resolveActivity(intent, resolvedType, 0, null, null, userId);
-            if ((aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
+            if (aInfo != null && (aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
                 throw new SecurityException(
                         "Attempt to embed activity that has not set allowEmbedded=\"true\"");
             }
@@ -3238,9 +3238,9 @@
             } else {
                 mContainerState = CONTAINER_STATE_NO_SURFACE;
                 ((VirtualActivityDisplay) mActivityDisplay).setSurface(null);
-//                if (mStack.mPausingActivity == null && mStack.mResumedActivity != null) {
-//                    mStack.startPausingLocked(false, true);
-//                }
+                if (mStack.mPausingActivity == null && mStack.mResumedActivity != null) {
+                    mStack.startPausingLocked(false, true);
+                }
             }
 
             setSurfaceIfReady();
@@ -3250,6 +3250,11 @@
         }
 
         @Override
+        boolean isAttached() {
+            return mSurface != null && super.isAttached();
+        }
+
+        @Override
         void setDrawn() {
             synchronized (mService) {
                 mDrawn = true;
diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java
index ce4c1ed..b41b478 100644
--- a/services/core/java/com/android/server/notification/NotificationDelegate.java
+++ b/services/core/java/com/android/server/notification/NotificationDelegate.java
@@ -21,8 +21,7 @@
 public interface NotificationDelegate {
     void onSetDisabled(int status);
     void onClearAll(int callingUid, int callingPid, int userId);
-    void onNotificationClick(int callingUid, int callingPid,
-            String pkg, String tag, int id, int userId);
+    void onNotificationClick(int callingUid, int callingPid, String key);
     void onNotificationClear(int callingUid, int callingPid,
             String pkg, String tag, int id, int userId);
     void onNotificationError(int callingUid, int callingPid,
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6ceee5c..7aa5d79 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -602,10 +602,20 @@
         }
 
         @Override
-        public void onNotificationClick(int callingUid, int callingPid,
-                String pkg, String tag, int id, int userId) {
-            cancelNotification(callingUid, callingPid, pkg, tag, id, Notification.FLAG_AUTO_CANCEL,
-                    Notification.FLAG_FOREGROUND_SERVICE, false, userId, REASON_DELEGATE_CLICK, null);
+        public void onNotificationClick(int callingUid, int callingPid, String key) {
+            synchronized (mNotificationList) {
+                EventLogTags.writeNotificationClicked(key);
+                NotificationRecord r = mNotificationsByKey.get(key);
+                if (r == null) {
+                    Log.w(TAG, "No notification with key: " + key);
+                    return;
+                }
+                StatusBarNotification sbn = r.sbn;
+                cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
+                        sbn.getId(), Notification.FLAG_AUTO_CANCEL,
+                        Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
+                        REASON_DELEGATE_CLICK, null);
+            }
         }
 
         @Override
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 91f796b..022bdae 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -546,13 +546,13 @@
     }
 
     @Override
-    public void onNotificationClick(String pkg, String tag, int id, int userId) {
+    public void onNotificationClick(String key) {
         enforceStatusBarService();
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
         long identity = Binder.clearCallingIdentity();
         try {
-            mNotificationDelegate.onNotificationClick(callingUid, callingPid, pkg, tag, id, userId);
+            mNotificationDelegate.onNotificationClick(callingUid, callingPid, key);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 045c0f6..16afc8f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -28,6 +28,8 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.voice.IVoiceInteractionService;
@@ -88,6 +90,21 @@
         private boolean mSafeMode;
         private int mCurUser;
 
+        @Override
+        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+                throws RemoteException {
+            try {
+                return super.onTransact(code, data, reply, flags);
+            } catch (RuntimeException e) {
+                // The activity manager only throws security exceptions, so let's
+                // log all others.
+                if (!(e instanceof SecurityException)) {
+                    Slog.wtf(TAG, "VoiceInteractionManagerService Crash", e);
+                }
+                throw e;
+            }
+        }
+
         public void systemRunning(boolean safeMode) {
             mSafeMode = safeMode;
 
@@ -97,18 +114,18 @@
 
             synchronized (this) {
                 mCurUser = ActivityManager.getCurrentUser();
-                switchImplementationIfNeededLocked();
+                switchImplementationIfNeededLocked(false);
             }
         }
 
         public void switchUser(int userHandle) {
             synchronized (this) {
                 mCurUser = userHandle;
-                switchImplementationIfNeededLocked();
+                switchImplementationIfNeededLocked(false);
             }
         }
 
-        void switchImplementationIfNeededLocked() {
+        void switchImplementationIfNeededLocked(boolean force) {
             if (!mSafeMode) {
                 String curService = Settings.Secure.getStringForUser(
                         mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
@@ -121,7 +138,7 @@
                         serviceComponent = null;
                     }
                 }
-                if (mImpl == null || mImpl.mUser != mCurUser
+                if (force || mImpl == null || mImpl.mUser != mCurUser
                         || !mImpl.mComponent.equals(serviceComponent)) {
                     if (mImpl != null) {
                         mImpl.shutdownLocked();
@@ -138,10 +155,10 @@
         }
 
         @Override
-        public void startVoiceActivity(Intent intent, String resolvedType,
-                IVoiceInteractionService service, Bundle args) {
+        public void startSession(IVoiceInteractionService service, Bundle args) {
             synchronized (this) {
-                if (mImpl == null || service.asBinder() != mImpl.mService.asBinder()) {
+                if (mImpl == null || mImpl.mService == null
+                        || service.asBinder() != mImpl.mService.asBinder()) {
                     throw new SecurityException(
                             "Caller is not the current voice interaction service");
                 }
@@ -149,8 +166,7 @@
                 final int callingUid = Binder.getCallingUid();
                 final long caller = Binder.clearCallingIdentity();
                 try {
-                    mImpl.startVoiceActivityLocked(callingPid, callingUid,
-                            intent, resolvedType, args);
+                    mImpl.startSessionLocked(callingPid, callingUid, args);
                 } finally {
                     Binder.restoreCallingIdentity(caller);
                 }
@@ -158,12 +174,12 @@
         }
 
         @Override
-        public int deliverNewSession(IBinder token, IVoiceInteractionSession session,
+        public boolean deliverNewSession(IBinder token, IVoiceInteractionSession session,
                 IVoiceInteractor interactor) {
             synchronized (this) {
                 if (mImpl == null) {
-                    Slog.w(TAG, "deliverNewSession without running voice interaction service");
-                    return ActivityManager.START_CANCELED;
+                    throw new SecurityException(
+                            "deliverNewSession without running voice interaction service");
                 }
                 final int callingPid = Binder.getCallingPid();
                 final int callingUid = Binder.getCallingUid();
@@ -175,7 +191,43 @@
                     Binder.restoreCallingIdentity(caller);
                 }
             }
+        }
 
+        @Override
+        public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) {
+            synchronized (this) {
+                if (mImpl == null) {
+                    Slog.w(TAG, "startVoiceActivity without running voice interaction service");
+                    return ActivityManager.START_CANCELED;
+                }
+                final int callingPid = Binder.getCallingPid();
+                final int callingUid = Binder.getCallingUid();
+                final long caller = Binder.clearCallingIdentity();
+                try {
+                    return mImpl.startVoiceActivityLocked(callingPid, callingUid, token,
+                            intent, resolvedType);
+                } finally {
+                    Binder.restoreCallingIdentity(caller);
+                }
+            }
+        }
+
+        @Override
+        public void finish(IBinder token) {
+            synchronized (this) {
+                if (mImpl == null) {
+                    Slog.w(TAG, "finish without running voice interaction service");
+                    return;
+                }
+                final int callingPid = Binder.getCallingPid();
+                final int callingUid = Binder.getCallingUid();
+                final long caller = Binder.clearCallingIdentity();
+                try {
+                    mImpl.finishLocked(callingPid, callingUid, token);
+                } finally {
+                    Binder.restoreCallingIdentity(caller);
+                }
+            }
         }
 
         @Override
@@ -207,7 +259,7 @@
 
             @Override public void onChange(boolean selfChange) {
                 synchronized (VoiceInteractionManagerServiceStub.this) {
-                    switchImplementationIfNeededLocked();
+                    switchImplementationIfNeededLocked(false);
                 }
             }
         }
@@ -220,27 +272,25 @@
 
             @Override
             public void onHandleUserStop(Intent intent, int userHandle) {
-                super.onHandleUserStop(intent, userHandle);
             }
 
             @Override
             public void onPackageDisappeared(String packageName, int reason) {
-                super.onPackageDisappeared(packageName, reason);
             }
 
             @Override
             public void onPackageAppeared(String packageName, int reason) {
-                super.onPackageAppeared(packageName, reason);
+                if (mImpl != null && packageName.equals(mImpl.mComponent.getPackageName())) {
+                    switchImplementationIfNeededLocked(true);
+                }
             }
 
             @Override
             public void onPackageModified(String packageName) {
-                super.onPackageModified(packageName);
             }
 
             @Override
             public void onSomePackagesChanged() {
-                super.onSomePackagesChanged();
             }
         };
     }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 6bbd1c1..9b6daad 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -19,9 +19,11 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
@@ -30,6 +32,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionService;
 import android.service.voice.IVoiceInteractionSession;
@@ -37,6 +40,8 @@
 import android.service.voice.VoiceInteractionService;
 import android.service.voice.VoiceInteractionServiceInfo;
 import android.util.Slog;
+import android.view.IWindowManager;
+import android.view.WindowManager;
 import com.android.internal.app.IVoiceInteractor;
 
 import java.io.FileDescriptor;
@@ -55,11 +60,28 @@
     final IActivityManager mAm;
     final VoiceInteractionServiceInfo mInfo;
     final ComponentName mSessionComponentName;
+    final IWindowManager mIWindowManager;
     boolean mBound = false;
     IVoiceInteractionService mService;
 
     SessionConnection mActiveSession;
 
+    final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+                synchronized (mLock) {
+                    if (mActiveSession != null && mActiveSession.mSession != null) {
+                        try {
+                            mActiveSession.mSession.closeSystemDialogs();
+                        } catch (RemoteException e) {
+                        }
+                    }
+                }
+            }
+        }
+    };
+
     final ServiceConnection mConnection = new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
@@ -76,23 +98,26 @@
 
     final class SessionConnection implements ServiceConnection {
         final IBinder mToken = new Binder();
-        final Intent mIntent;
-        final String mResolvedType;
         final Bundle mArgs;
         boolean mBound;
         IVoiceInteractionSessionService mService;
         IVoiceInteractionSession mSession;
         IVoiceInteractor mInteractor;
 
-        SessionConnection(Intent intent, String resolvedType, Bundle args) {
-            mIntent = intent;
-            mResolvedType = resolvedType;
+        SessionConnection(Bundle args) {
             mArgs = args;
             Intent serviceIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
             serviceIntent.setComponent(mSessionComponentName);
             mBound = mContext.bindServiceAsUser(serviceIntent, this,
                     Context.BIND_AUTO_CREATE, new UserHandle(mUser));
-            if (!mBound) {
+            if (mBound) {
+                try {
+                    mIWindowManager.addWindowToken(mToken,
+                            WindowManager.LayoutParams.TYPE_INPUT_METHOD);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed adding window token", e);
+                }
+            } else {
                 Slog.w(TAG, "Failed binding to voice interaction session service " + mComponent);
             }
         }
@@ -105,7 +130,7 @@
                     try {
                         mService.newSession(mToken, mArgs);
                     } catch (RemoteException e) {
-                        Slog.w(TAG, "Failed making new session", e);
+                        Slog.w(TAG, "Failed adding window token", e);
                     }
                 }
             }
@@ -118,7 +143,19 @@
 
         public void cancel() {
             if (mBound) {
+                if (mSession != null) {
+                    try {
+                        mSession.destroy();
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, "Voice interation session already dead");
+                    }
+                }
                 mContext.unbindService(this);
+                try {
+                    mIWindowManager.removeWindowToken(mToken);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed removing window token", e);
+                }
                 mBound = false;
                 mService = null;
                 mSession = null;
@@ -128,8 +165,6 @@
 
         public void dump(String prefix, PrintWriter pw) {
             pw.print(prefix); pw.print("mToken="); pw.println(mToken);
-            pw.print(prefix); pw.print("mIntent="); pw.println(mIntent);
-                    pw.print(" mResolvedType="); pw.println(mResolvedType);
             pw.print(prefix); pw.print("mArgs="); pw.println(mArgs);
             pw.print(prefix); pw.print("mBound="); pw.println(mBound);
             if (mBound) {
@@ -155,6 +190,7 @@
             Slog.w(TAG, "Voice interaction service not found: " + service);
             mInfo = null;
             mSessionComponentName = null;
+            mIWindowManager = null;
             mValid = false;
             return;
         }
@@ -162,43 +198,67 @@
         if (mInfo.getParseError() != null) {
             Slog.w(TAG, "Bad voice interaction service: " + mInfo.getParseError());
             mSessionComponentName = null;
+            mIWindowManager = null;
             mValid = false;
             return;
         }
         mValid = true;
         mSessionComponentName = new ComponentName(service.getPackageName(),
                 mInfo.getSessionService());
+        mIWindowManager = IWindowManager.Stub.asInterface(
+                ServiceManager.getService(Context.WINDOW_SERVICE));
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        mContext.registerReceiver(mBroadcastReceiver, filter, null, handler);
     }
 
-    public void startVoiceActivityLocked(int callingPid, int callingUid, Intent intent,
-            String resolvedType, Bundle args) {
+    public void startSessionLocked(int callingPid, int callingUid, Bundle args) {
         if (mActiveSession != null) {
             mActiveSession.cancel();
             mActiveSession = null;
         }
-        mActiveSession = new SessionConnection(intent, resolvedType, args);
-        intent.addCategory(Intent.CATEGORY_VOICE);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+        mActiveSession = new SessionConnection(args);
     }
 
-    public int deliverNewSessionLocked(int callingPid, int callingUid, IBinder token,
+    public boolean deliverNewSessionLocked(int callingPid, int callingUid, IBinder token,
             IVoiceInteractionSession session, IVoiceInteractor interactor) {
+        if (mActiveSession == null || token != mActiveSession.mToken) {
+            Slog.w(TAG, "deliverNewSession does not match active session");
+            return false;
+        }
+        mActiveSession.mSession = session;
+        mActiveSession.mInteractor = interactor;
+        return true;
+    }
+
+    public int startVoiceActivityLocked(int callingPid, int callingUid, IBinder token,
+            Intent intent, String resolvedType) {
         try {
             if (mActiveSession == null || token != mActiveSession.mToken) {
-                Slog.w(TAG, "deliverNewSession does not match active session");
+                Slog.w(TAG, "startVoiceActivity does not match active session");
                 return ActivityManager.START_CANCELED;
             }
-            mActiveSession.mSession = session;
-            mActiveSession.mInteractor = interactor;
+            intent = new Intent(intent);
+            intent.addCategory(Intent.CATEGORY_VOICE);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
             return mAm.startVoiceActivity(mComponent.getPackageName(), callingPid, callingUid,
-                    mActiveSession.mIntent, mActiveSession.mResolvedType,
-                    mActiveSession.mSession, mActiveSession.mInteractor,
+                    intent, resolvedType, mActiveSession.mSession, mActiveSession.mInteractor,
                     0, null, null, null, mUser);
         } catch (RemoteException e) {
             throw new IllegalStateException("Unexpected remote error", e);
         }
     }
 
+
+    public void finishLocked(int callingPid, int callingUid, IBinder token) {
+        if (mActiveSession == null || token != mActiveSession.mToken) {
+            Slog.w(TAG, "finish does not match active session");
+            return;
+        }
+        mActiveSession.cancel();
+        mActiveSession = null;
+    }
+
     public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!mValid) {
             pw.print("  NOT VALID: ");
@@ -234,5 +294,8 @@
             mContext.unbindService(mConnection);
             mBound = false;
         }
+        if (mValid) {
+            mContext.unregisterReceiver(mBroadcastReceiver);
+        }
     }
 }
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
index f060bc8..5c273de1 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
@@ -27,6 +27,9 @@
 import android.view.HardwareCanvas;
 import android.view.RenderNodeAnimator;
 import android.view.View;
+import android.webkit.WebChromeClient;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
 import android.widget.LinearLayout;
 import android.widget.LinearLayout.LayoutParams;
 import android.widget.ProgressBar;
@@ -43,6 +46,12 @@
 
         ProgressBar spinner = new ProgressBar(this, null, android.R.attr.progressBarStyleLarge);
         layout.addView(spinner, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+        // For testing with a functor in the tree
+//        WebView wv = new WebView(this);
+//        wv.setWebViewClient(new WebViewClient());
+//        wv.setWebChromeClient(new WebChromeClient());
+//        wv.loadUrl("http://theverge.com");
+//        layout.addView(wv, new LayoutParams(LayoutParams.MATCH_PARENT, 100));
 
         layout.addView(new CircleView(this),
                 new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
diff --git a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
new file mode 100644
index 0000000..9fcbf3e
--- /dev/null
+++ b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:background="#ffffffff"
+    >
+
+    <TextView android:id="@+id/text"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="32dp"
+        />
+
+    <Button android:id="@+id/start"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/start"
+        />
+
+</LinearLayout>
+
+
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
index 008d97b..d40b05f 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
@@ -17,6 +17,7 @@
 package com.android.test.voiceinteraction;
 
 import android.content.Intent;
+import android.os.Bundle;
 import android.service.voice.VoiceInteractionService;
 import android.util.Log;
 
@@ -31,7 +32,9 @@
 
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
-        startVoiceActivity(new Intent(this, TestInteractionActivity.class), null);
+        Bundle args = new Bundle();
+        args.putParcelable("intent", new Intent(this, TestInteractionActivity.class));
+        startSession(args);
         stopSelf(startId);
         return START_NOT_STICKY;
     }
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index 0fc563b..a3af284 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -17,18 +17,59 @@
 package com.android.test.voiceinteraction;
 
 import android.content.Context;
+import android.content.Intent;
 import android.os.Bundle;
 import android.service.voice.VoiceInteractionSession;
 import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
 
-public class MainInteractionSession extends VoiceInteractionSession {
+public class MainInteractionSession extends VoiceInteractionSession
+        implements View.OnClickListener {
     static final String TAG = "MainInteractionSession";
 
-    final Bundle mArgs;
+    Intent mStartIntent;
+    View mContentView;
+    TextView mText;
+    Button mStartButton;
 
-    MainInteractionSession(Context context, Bundle args) {
+    Request mPendingRequest;
+    boolean mPendingConfirm;
+
+    MainInteractionSession(Context context) {
         super(context);
-        mArgs = args;
+    }
+
+    @Override
+    public void onCreate(Bundle args) {
+        super.onCreate(args);
+        showWindow();
+        mStartIntent = args.getParcelable("intent");
+    }
+
+    @Override
+    public View onCreateContentView() {
+        mContentView = getLayoutInflater().inflate(R.layout.voice_interaction_session, null);
+        mText = (TextView)mContentView.findViewById(R.id.text);
+        mStartButton = (Button)mContentView.findViewById(R.id.start);
+        mStartButton.setOnClickListener(this);
+        return mContentView;
+    }
+
+    public void onClick(View v) {
+        if (mPendingRequest == null) {
+            mStartButton.setEnabled(false);
+            startVoiceActivity(mStartIntent);
+        } else {
+            if (mPendingConfirm) {
+                mPendingRequest.sendConfirmResult(true, null);
+            } else {
+                mPendingRequest.sendCommandResult(true, null);
+            }
+            mPendingRequest = null;
+            mStartButton.setText("Start");
+        }
     }
 
     @Override
@@ -38,14 +79,22 @@
 
     @Override
     public void onConfirm(Caller caller, Request request, String prompt, Bundle extras) {
-        Log.i(TAG, "onConform: prompt=" + prompt + " extras=" + extras);
-        request.sendConfirmResult(true, null);
+        Log.i(TAG, "onConfirm: prompt=" + prompt + " extras=" + extras);
+        mText.setText(prompt);
+        mStartButton.setEnabled(true);
+        mStartButton.setText("Confirm");
+        mPendingRequest = request;
+        mPendingConfirm = true;
     }
 
     @Override
     public void onCommand(Caller caller, Request request, String command, Bundle extras) {
         Log.i(TAG, "onCommand: command=" + command + " extras=" + extras);
-        request.sendCommandResult(true, null);
+        mText.setText("Command: " + command);
+        mStartButton.setEnabled(true);
+        mStartButton.setText("Finish Command");
+        mPendingRequest = request;
+        mPendingConfirm = false;
     }
 
     @Override
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java
index 8864d71..7cf8178 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java
@@ -23,6 +23,6 @@
 public class MainInteractionSessionService extends VoiceInteractionSessionService {
     @Override
     public VoiceInteractionSession onNewSession(Bundle args) {
-        return new MainInteractionSession(this, args);
+        return new MainInteractionSession(this);
     }
 }
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index d0581f6..1348be3 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1261,12 +1261,13 @@
         while ((err=it.next()) == NO_ERROR) {
             String8 src = it.getFile()->getPrintableSource();
             err = compileXmlFile(assets, it.getFile(), &table, xmlFlags);
-            if (err != NO_ERROR) {
+            if (err == NO_ERROR) {
+                ResXMLTree block;
+                block.setTo(it.getFile()->getData(), it.getFile()->getSize(), true);
+                checkForIds(src, block);
+            } else {
                 hasErrors = true;
             }
-            ResXMLTree block;
-            block.setTo(it.getFile()->getData(), it.getFile()->getSize(), true);
-            checkForIds(src, block);
         }
 
         if (err < NO_ERROR) {