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) {