Merge "Improve documentation of setOnFrameAvailableListener."
diff --git a/Android.mk b/Android.mk
index 8e283d7..99d73fa 100644
--- a/Android.mk
+++ b/Android.mk
@@ -199,6 +199,8 @@
core/java/android/service/dreams/IDozeHardware.aidl \
core/java/android/service/dreams/IDreamManager.aidl \
core/java/android/service/dreams/IDreamService.aidl \
+ core/java/android/service/fingerprint/IFingerprintService.aidl \
+ core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl \
core/java/android/service/trust/ITrustAgentService.aidl \
core/java/android/service/trust/ITrustAgentServiceCallback.aidl \
core/java/android/service/voice/IVoiceInteractionService.aidl \
@@ -318,6 +320,7 @@
wifi/java/android/net/wifi/IWifiManager.aidl \
wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl \
wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
+ wifi/java/android/net/wifi/IWifiScanner.aidl \
packages/services/PacProcessor/com/android/net/IProxyService.aidl \
packages/services/Proxy/com/android/net/IProxyCallback.aidl \
packages/services/Proxy/com/android/net/IProxyPortListener.aidl \
@@ -718,8 +721,9 @@
$(full_target): $(framework_built) $(gen)
# Run this for checkbuild
-.PHONY: checkbuild
checkbuild: doc-comment-check-docs
+# Check comment when you are updating the API
+update-api: doc-comment-check-docs
# ==== static html in the sdk ==================================
include $(CLEAR_VARS)
diff --git a/api/current.txt b/api/current.txt
index 071db5a..edc8700 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -250,7 +250,7 @@
field public static final int actionBarTabBarStyle = 16843508; // 0x10102f4
field public static final int actionBarTabStyle = 16843507; // 0x10102f3
field public static final int actionBarTabTextStyle = 16843509; // 0x10102f5
- field public static final int actionBarTheme = 16843837; // 0x101043d
+ field public static final int actionBarTheme = 16843831; // 0x1010437
field public static final int actionBarWidgetTheme = 16843671; // 0x1010397
field public static final int actionButtonStyle = 16843480; // 0x10102d8
field public static final int actionDropDownStyle = 16843479; // 0x10102d7
@@ -267,7 +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 actionOverflowMenuStyle = 16843851; // 0x101044b
field public static final int actionProviderClass = 16843657; // 0x1010389
field public static final int actionViewClass = 16843516; // 0x10102fc
field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
@@ -295,7 +295,6 @@
field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef
field public static final int alwaysRetainTaskState = 16843267; // 0x1010203
field public static final int angle = 16843168; // 0x10101a0
- field public static final int animate = 16843823; // 0x101042f
field public static final int animateFirstView = 16843477; // 0x10102d5
field public static final int animateLayoutChanges = 16843506; // 0x10102f2
field public static final int animateOnClick = 16843356; // 0x101025c
@@ -314,6 +313,7 @@
field public static final int autoCompleteTextViewStyle = 16842859; // 0x101006b
field public static final int autoLink = 16842928; // 0x10100b0
field public static final int autoMirrored = 16843754; // 0x10103ea
+ field public static final int autoRemoveFromRecents = 16843853; // 0x101044d
field public static final int autoStart = 16843445; // 0x10102b5
field public static final deprecated int autoText = 16843114; // 0x101016a
field public static final int autoUrlDetect = 16843404; // 0x101028c
@@ -382,29 +382,29 @@
field public static final int clipChildren = 16842986; // 0x10100ea
field public static final int clipOrientation = 16843274; // 0x101020a
field public static final int clipToPadding = 16842987; // 0x10100eb
- field public static final int clipToPath = 16843822; // 0x101042e
+ field public static final int clipToPath = 16843818; // 0x101042a
field public static final int codes = 16843330; // 0x1010242
field public static final int collapseColumns = 16843083; // 0x101014b
field public static final int color = 16843173; // 0x10101a5
- field public static final int colorAccent = 16843842; // 0x1010442
+ field public static final int colorAccent = 16843836; // 0x101043c
field public static final int colorActivatedHighlight = 16843664; // 0x1010390
field public static final int colorBackground = 16842801; // 0x1010031
field public static final int colorBackgroundCacheHint = 16843435; // 0x10102ab
- field public static final int colorButtonNormal = 16843829; // 0x1010435
- field public static final int colorButtonNormalColored = 16843831; // 0x1010437
- field public static final int colorButtonPressed = 16843830; // 0x1010436
- field public static final int colorButtonPressedColored = 16843832; // 0x1010438
- field public static final int colorControlActivated = 16843828; // 0x1010434
- field public static final int colorControlNormal = 16843827; // 0x1010433
+ field public static final int colorButtonNormal = 16843823; // 0x101042f
+ field public static final int colorButtonNormalColored = 16843825; // 0x1010431
+ field public static final int colorButtonPressed = 16843824; // 0x1010430
+ field public static final int colorButtonPressedColored = 16843826; // 0x1010432
+ field public static final int colorControlActivated = 16843822; // 0x101042e
+ field public static final int colorControlNormal = 16843821; // 0x101042d
field public static final int colorFocusedHighlight = 16843663; // 0x101038f
field public static final int colorForeground = 16842800; // 0x1010030
field public static final int colorForegroundInverse = 16843270; // 0x1010206
field public static final int colorLongPressedHighlight = 16843662; // 0x101038e
field public static final int colorMultiSelectHighlight = 16843665; // 0x1010391
field public static final int colorPressedHighlight = 16843661; // 0x101038d
- field public static final int colorPrimary = 16843840; // 0x1010440
- field public static final int colorPrimaryDark = 16843841; // 0x1010441
- field public static final int colorPrimaryLight = 16843839; // 0x101043f
+ field public static final int colorPrimary = 16843834; // 0x101043a
+ field public static final int colorPrimaryDark = 16843835; // 0x101043b
+ field public static final int colorPrimaryLight = 16843833; // 0x1010439
field public static final int columnCount = 16843639; // 0x1010377
field public static final int columnDelay = 16843215; // 0x10101cf
field public static final int columnOrderPreserved = 16843640; // 0x1010378
@@ -463,6 +463,7 @@
field public static final int dividerHorizontal = 16843564; // 0x101032c
field public static final int dividerPadding = 16843562; // 0x101032a
field public static final int dividerVertical = 16843530; // 0x101030a
+ field public static final int documentLaunchMode = 16843852; // 0x101044c
field public static final int drawSelectorOnTop = 16843004; // 0x10100fc
field public static final int drawable = 16843161; // 0x1010199
field public static final int drawableBottom = 16843118; // 0x101016e
@@ -485,14 +486,13 @@
field public static final int dropDownWidth = 16843362; // 0x1010262
field public static final int duplicateParentState = 16842985; // 0x10100e9
field public static final int duration = 16843160; // 0x1010198
- field public static final int durations = 16843814; // 0x1010426
field public static final int editTextBackground = 16843602; // 0x1010352
field public static final int editTextColor = 16843601; // 0x1010351
field public static final int editTextPreferenceStyle = 16842898; // 0x1010092
field public static final int editTextStyle = 16842862; // 0x101006e
field public static final deprecated int editable = 16843115; // 0x101016b
field public static final int editorExtras = 16843300; // 0x1010224
- field public static final int elevation = 16843853; // 0x101044d
+ field public static final int elevation = 16843847; // 0x1010447
field public static final int ellipsize = 16842923; // 0x10100ab
field public static final int ems = 16843096; // 0x1010158
field public static final int enabled = 16842766; // 0x101000e
@@ -502,9 +502,9 @@
field public static final int entries = 16842930; // 0x10100b2
field public static final int entryValues = 16843256; // 0x10101f8
field public static final int eventsInterceptionEnabled = 16843389; // 0x101027d
- field public static final int excludeClass = 16843855; // 0x101044f
+ field public static final int excludeClass = 16843849; // 0x1010449
field public static final int excludeFromRecents = 16842775; // 0x1010017
- field public static final int excludeId = 16843854; // 0x101044e
+ field public static final int excludeId = 16843848; // 0x1010448
field public static final int exitFadeDuration = 16843533; // 0x101030d
field public static final int expandableListPreferredChildIndicatorLeft = 16842834; // 0x1010052
field public static final int expandableListPreferredChildIndicatorRight = 16842835; // 0x1010053
@@ -533,11 +533,11 @@
field public static final int fastScrollTextColor = 16843609; // 0x1010359
field public static final int fastScrollThumbDrawable = 16843574; // 0x1010336
field public static final int fastScrollTrackDrawable = 16843577; // 0x1010339
- field public static final int fill = 16843809; // 0x1010421
+ field public static final int fill = 16843808; // 0x1010420
field public static final int fillAfter = 16843197; // 0x10101bd
field public static final int fillBefore = 16843196; // 0x10101bc
field public static final int fillEnabled = 16843343; // 0x101024f
- field public static final int fillOpacity = 16843808; // 0x1010420
+ field public static final int fillOpacity = 16843807; // 0x101041f
field public static final int fillViewport = 16843130; // 0x101017a
field public static final int filter = 16843035; // 0x101011b
field public static final int filterTouchesWhenObscured = 16843460; // 0x10102c4
@@ -599,7 +599,7 @@
field public static final int headerBackground = 16843055; // 0x101012f
field public static final int headerDividersEnabled = 16843310; // 0x101022e
field public static final int height = 16843093; // 0x1010155
- field public static final int hideOnContentScroll = 16843856; // 0x1010450
+ field public static final int hideOnContentScroll = 16843850; // 0x101044a
field public static final int hint = 16843088; // 0x1010150
field public static final int homeAsUpIndicator = 16843531; // 0x101030b
field public static final int homeLayout = 16843549; // 0x101031d
@@ -769,7 +769,6 @@
field public static final int layout_x = 16843135; // 0x101017f
field public static final int layout_y = 16843136; // 0x1010180
field public static final int left = 16843181; // 0x10101ad
- field public static final int limitTo = 16843824; // 0x1010430
field public static final int lineSpacingExtra = 16843287; // 0x1010217
field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
field public static final int lines = 16843092; // 0x1010154
@@ -831,7 +830,7 @@
field public static final int name = 16842755; // 0x1010003
field public static final int navigationMode = 16843471; // 0x10102cf
field public static final int negativeButtonText = 16843254; // 0x10101f6
- field public static final int nestedScrollingEnabled = 16843843; // 0x1010443
+ field public static final int nestedScrollingEnabled = 16843837; // 0x101043d
field public static final int nextFocusDown = 16842980; // 0x10100e4
field public static final int nextFocusForward = 16843580; // 0x101033c
field public static final int nextFocusLeft = 16842977; // 0x10100e1
@@ -873,18 +872,18 @@
field public static final int parentActivityName = 16843687; // 0x10103a7
field public static final deprecated int password = 16843100; // 0x101015c
field public static final int path = 16842794; // 0x101002a
- field public static final int pathData = 16843810; // 0x1010422
+ field public static final int pathData = 16843809; // 0x1010421
field public static final int pathPattern = 16842796; // 0x101002c
field public static final int pathPrefix = 16842795; // 0x101002b
field public static final int permission = 16842758; // 0x1010006
field public static final int permissionFlags = 16843719; // 0x10103c7
field public static final int permissionGroup = 16842762; // 0x101000a
field public static final int permissionGroupFlags = 16843717; // 0x10103c5
- field public static final int persistable = 16843833; // 0x1010439
+ field public static final int persistable = 16843827; // 0x1010433
field public static final int persistent = 16842765; // 0x101000d
field public static final int persistentDrawingCache = 16842990; // 0x10100ee
field public static final deprecated int phoneNumber = 16843111; // 0x1010167
- field public static final int pinned = 16843826; // 0x1010432
+ field public static final int pinned = 16843820; // 0x101042c
field public static final int pivotX = 16843189; // 0x10101b5
field public static final int pivotY = 16843190; // 0x10101b6
field public static final int popupAnimationStyle = 16843465; // 0x10102c9
@@ -939,7 +938,6 @@
field public static final int readPermission = 16842759; // 0x1010007
field public static final int repeatCount = 16843199; // 0x10101bf
field public static final int repeatMode = 16843200; // 0x10101c0
- field public static final int repeatStyle = 16843816; // 0x1010428
field public static final int reqFiveWayNav = 16843314; // 0x1010232
field public static final int reqHardKeyboard = 16843305; // 0x1010229
field public static final int reqKeyboardType = 16843304; // 0x1010228
@@ -949,7 +947,7 @@
field public static final int required = 16843406; // 0x101028e
field public static final int requiredAccountType = 16843734; // 0x10103d6
field public static final int requiredForAllUsers = 16843728; // 0x10103d0
- field public static final int requiredForProfile = 16843825; // 0x1010431
+ field public static final int requiredForProfile = 16843819; // 0x101042b
field public static final int requiresFadingEdge = 16843685; // 0x10103a5
field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
field public static final int resizeMode = 16843619; // 0x1010363
@@ -1013,8 +1011,7 @@
field public static final int selectableItemBackground = 16843534; // 0x101030e
field public static final int selectedDateVerticalBar = 16843591; // 0x1010347
field public static final int selectedWeekBackgroundColor = 16843586; // 0x1010342
- field public static final int sequence = 16843815; // 0x1010427
- field public static final int sessionService = 16843850; // 0x101044a
+ field public static final int sessionService = 16843844; // 0x1010444
field public static final int settingsActivity = 16843301; // 0x1010225
field public static final int shadowColor = 16843105; // 0x1010161
field public static final int shadowDx = 16843106; // 0x1010162
@@ -1036,7 +1033,7 @@
field public static final int shrinkColumns = 16843082; // 0x101014a
field public static final deprecated int singleLine = 16843101; // 0x101015d
field public static final int singleUser = 16843711; // 0x10103bf
- field public static final int slideEdge = 16843836; // 0x101043c
+ field public static final int slideEdge = 16843830; // 0x1010436
field public static final int smallIcon = 16843422; // 0x101029e
field public static final int smallScreens = 16843396; // 0x1010284
field public static final int smoothScrollbar = 16843313; // 0x1010231
@@ -1053,12 +1050,13 @@
field public static final int sspPattern = 16843749; // 0x10103e5
field public static final int sspPrefix = 16843748; // 0x10103e4
field public static final int stackFromBottom = 16843005; // 0x10100fd
- field public static final int stackViewStyle = 16843851; // 0x101044b
+ field public static final int stackViewStyle = 16843845; // 0x1010445
field public static final int starStyle = 16842882; // 0x1010082
field public static final int startColor = 16843165; // 0x101019d
field public static final int startDelay = 16843746; // 0x10103e2
field public static final int startOffset = 16843198; // 0x10101be
field public static final deprecated int startYear = 16843132; // 0x101017c
+ field public static final int stateListAnimator = 16843854; // 0x101044e
field public static final int stateNotNeeded = 16842774; // 0x1010016
field public static final int state_above_anchor = 16842922; // 0x10100aa
field public static final int state_accelerated = 16843547; // 0x101031b
@@ -1088,13 +1086,13 @@
field public static final int streamType = 16843273; // 0x1010209
field public static final int stretchColumns = 16843081; // 0x1010149
field public static final int stretchMode = 16843030; // 0x1010116
- field public static final int stroke = 16843811; // 0x1010423
- field public static final int strokeLineCap = 16843820; // 0x101042c
- field public static final int strokeLineJoin = 16843821; // 0x101042d
- field public static final int strokeOpacity = 16843812; // 0x1010424
- field public static final int strokeWidth = 16843813; // 0x1010425
+ field public static final int stroke = 16843810; // 0x1010422
+ field public static final int strokeLineCap = 16843816; // 0x1010428
+ field public static final int strokeLineJoin = 16843817; // 0x1010429
+ field public static final int strokeOpacity = 16843811; // 0x1010423
+ field public static final int strokeWidth = 16843812; // 0x1010424
field public static final int subtitle = 16843473; // 0x10102d1
- field public static final int subtitleTextAppearance = 16843835; // 0x101043b
+ field public static final int subtitleTextAppearance = 16843829; // 0x1010435
field public static final int subtitleTextStyle = 16843513; // 0x10102f9
field public static final int subtypeExtraValue = 16843674; // 0x101039a
field public static final int subtypeId = 16843713; // 0x10103c1
@@ -1111,7 +1109,7 @@
field public static final int switchMinWidth = 16843632; // 0x1010370
field public static final int switchPadding = 16843633; // 0x1010371
field public static final int switchPreferenceStyle = 16843629; // 0x101036d
- field public static final int switchStyle = 16843852; // 0x101044c
+ field public static final int switchStyle = 16843846; // 0x1010446
field public static final int switchTextAppearance = 16843630; // 0x101036e
field public static final int switchTextOff = 16843628; // 0x101036c
field public static final int switchTextOn = 16843627; // 0x101036b
@@ -1148,7 +1146,7 @@
field public static final int textAppearanceLargeInverse = 16842819; // 0x1010043
field public static final int textAppearanceLargePopupMenu = 16843521; // 0x1010301
field public static final int textAppearanceListItem = 16843678; // 0x101039e
- field public static final int textAppearanceListItemSecondary = 16843838; // 0x101043e
+ field public static final int textAppearanceListItemSecondary = 16843832; // 0x1010438
field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
field public static final int textAppearanceMedium = 16842817; // 0x1010041
field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
@@ -1212,7 +1210,7 @@
field public static final int tintMode = 16843798; // 0x1010416
field public static final int title = 16843233; // 0x10101e1
field public static final int titleCondensed = 16843234; // 0x10101e2
- field public static final int titleTextAppearance = 16843834; // 0x101043a
+ field public static final int titleTextAppearance = 16843828; // 0x1010434
field public static final int titleTextStyle = 16843512; // 0x10102f8
field public static final int toAlpha = 16843211; // 0x10101cb
field public static final int toDegrees = 16843188; // 0x10101b4
@@ -1237,10 +1235,9 @@
field public static final int translationX = 16843554; // 0x1010322
field public static final int translationY = 16843555; // 0x1010323
field public static final int translationZ = 16843797; // 0x1010415
- field public static final int trigger = 16843805; // 0x101041d
- field public static final int trimPathEnd = 16843818; // 0x101042a
- field public static final int trimPathOffset = 16843819; // 0x101042b
- field public static final int trimPathStart = 16843817; // 0x1010429
+ field public static final int trimPathEnd = 16843814; // 0x1010426
+ field public static final int trimPathOffset = 16843815; // 0x1010427
+ field public static final int trimPathStart = 16843813; // 0x1010425
field public static final int type = 16843169; // 0x10101a1
field public static final int typeface = 16842902; // 0x1010096
field public static final int uiOptions = 16843672; // 0x1010398
@@ -1265,8 +1262,8 @@
field public static final int verticalGap = 16843328; // 0x1010240
field public static final int verticalScrollbarPosition = 16843572; // 0x1010334
field public static final int verticalSpacing = 16843029; // 0x1010115
- field public static final int viewportHeight = 16843807; // 0x101041f
- field public static final int viewportWidth = 16843806; // 0x101041e
+ field public static final int viewportHeight = 16843806; // 0x101041e
+ field public static final int viewportWidth = 16843805; // 0x101041d
field public static final int visibility = 16842972; // 0x10100dc
field public static final int visible = 16843156; // 0x1010194
field public static final int vmSafeMode = 16843448; // 0x10102b8
@@ -1295,8 +1292,8 @@
field public static final int windowActionBar = 16843469; // 0x10102cd
field public static final int windowActionBarOverlay = 16843492; // 0x10102e4
field public static final int windowActionModeOverlay = 16843485; // 0x10102dd
- field public static final int windowAllowEnterTransitionOverlap = 16843849; // 0x1010449
- field public static final int windowAllowExitTransitionOverlap = 16843848; // 0x1010448
+ field public static final int windowAllowEnterTransitionOverlap = 16843843; // 0x1010443
+ field public static final int windowAllowExitTransitionOverlap = 16843842; // 0x1010442
field public static final int windowAnimationStyle = 16842926; // 0x10100ae
field public static final int windowBackground = 16842836; // 0x1010054
field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
@@ -1306,9 +1303,9 @@
field public static final int windowDisablePreview = 16843298; // 0x1010222
field public static final int windowEnableSplitTouch = 16843543; // 0x1010317
field public static final int windowEnterAnimation = 16842932; // 0x10100b4
- field public static final int windowEnterTransition = 16843844; // 0x1010444
+ field public static final int windowEnterTransition = 16843838; // 0x101043e
field public static final int windowExitAnimation = 16842933; // 0x10100b5
- field public static final int windowExitTransition = 16843845; // 0x1010445
+ field public static final int windowExitTransition = 16843839; // 0x101043f
field public static final int windowFrame = 16842837; // 0x1010055
field public static final int windowFullscreen = 16843277; // 0x101020d
field public static final int windowHideAnimation = 16842935; // 0x10100b7
@@ -1319,8 +1316,8 @@
field public static final int windowNoDisplay = 16843294; // 0x101021e
field public static final int windowNoTitle = 16842838; // 0x1010056
field public static final int windowOverscan = 16843727; // 0x10103cf
- field public static final int windowSharedElementEnterTransition = 16843846; // 0x1010446
- field public static final int windowSharedElementExitTransition = 16843847; // 0x1010447
+ field public static final int windowSharedElementEnterTransition = 16843840; // 0x1010440
+ field public static final int windowSharedElementExitTransition = 16843841; // 0x1010441
field public static final int windowShowAnimation = 16842934; // 0x10100b6
field public static final int windowShowWallpaper = 16843410; // 0x1010292
field public static final int windowSoftInputMode = 16843307; // 0x101022b
@@ -2786,6 +2783,7 @@
public class AnimatorInflater {
ctor public AnimatorInflater();
method public static android.animation.Animator loadAnimator(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
+ method public static android.animation.StateListAnimator loadStateListAnimator(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
}
public abstract class AnimatorListenerAdapter implements android.animation.Animator.AnimatorListener android.animation.Animator.AnimatorPauseListener {
@@ -2982,6 +2980,12 @@
method public android.graphics.Rect evaluate(float, android.graphics.Rect, android.graphics.Rect);
}
+ public class StateListAnimator {
+ ctor public StateListAnimator();
+ method public void addState(int[], android.animation.Animator);
+ method public void jumpToCurrentState();
+ }
+
public class TimeAnimator extends android.animation.ValueAnimator {
ctor public TimeAnimator();
method public void setTimeListener(android.animation.TimeAnimator.TimeListener);
@@ -3361,10 +3365,12 @@
method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
method public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
method public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+ method public void startLockTask();
method public deprecated void startManagingCursor(android.database.Cursor);
method public boolean startNextMatchingActivity(android.content.Intent);
method public boolean startNextMatchingActivity(android.content.Intent, android.os.Bundle);
method public void startSearch(java.lang.String, boolean, android.os.Bundle, boolean);
+ method public void stopLockTask();
method public deprecated void stopManagingCursor(android.database.Cursor);
method public void takeKeyEvents(boolean);
method public void triggerSearch(java.lang.String, android.os.Bundle);
@@ -4426,6 +4432,7 @@
field public static final java.lang.String CATEGORY_STATUS = "status";
field public static final java.lang.String CATEGORY_SYSTEM = "sys";
field public static final java.lang.String CATEGORY_TRANSPORT = "transport";
+ field public static final int COLOR_DEFAULT = 0; // 0x0
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int DEFAULT_ALL = -1; // 0xffffffff
field public static final int DEFAULT_LIGHTS = 4; // 0x4
@@ -4471,6 +4478,7 @@
field public int audioStreamType;
field public android.widget.RemoteViews bigContentView;
field public java.lang.String category;
+ field public int color;
field public android.app.PendingIntent contentIntent;
field public android.widget.RemoteViews contentView;
field public int defaults;
@@ -4533,6 +4541,7 @@
method public deprecated android.app.Notification getNotification();
method public android.app.Notification.Builder setAutoCancel(boolean);
method public android.app.Notification.Builder setCategory(java.lang.String);
+ method public android.app.Notification.Builder setColor(int);
method public android.app.Notification.Builder setContent(android.widget.RemoteViews);
method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);
@@ -5013,6 +5022,9 @@
method public void clearForwardingIntentFilters(android.content.ComponentName);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
+ method public void enableSystemApp(android.content.ComponentName, java.lang.String);
+ method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
+ method public java.lang.String[] getAccountTypesWithManagementDisabled();
method public java.util.List<android.content.ComponentName> getActiveAdmins();
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
method public boolean getCameraDisabled(android.content.ComponentName);
@@ -5042,6 +5054,7 @@
method public void lockNow();
method public void removeActiveAdmin(android.content.ComponentName);
method public boolean resetPassword(java.lang.String, int);
+ method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
method public void setCameraDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
@@ -6614,6 +6627,7 @@
field public static final java.lang.String DISPLAY_SERVICE = "display";
field public static final java.lang.String DOWNLOAD_SERVICE = "download";
field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
+ field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
field public static final java.lang.String HDMI_CEC_SERVICE = "hdmi_cec";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
@@ -7149,6 +7163,7 @@
field public static final int FILL_IN_PACKAGE = 16; // 0x10
field public static final int FILL_IN_SELECTOR = 64; // 0x40
field public static final int FILL_IN_SOURCE_BOUNDS = 32; // 0x20
+ field public static final int FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
field public static final int FLAG_ACTIVITY_BROUGHT_TO_FRONT = 4194304; // 0x400000
field public static final int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000
field public static final int FLAG_ACTIVITY_CLEAR_TOP = 67108864; // 0x4000000
@@ -7667,8 +7682,12 @@
field public static final int CONFIG_TOUCHSCREEN = 8; // 0x8
field public static final int CONFIG_UI_MODE = 512; // 0x200
field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int DOCUMENT_LAUNCH_ALWAYS = 2; // 0x2
+ field public static final int DOCUMENT_LAUNCH_INTO_EXISTING = 1; // 0x1
+ field public static final int DOCUMENT_LAUNCH_NONE = 0; // 0x0
field public static final int FLAG_ALLOW_TASK_REPARENTING = 64; // 0x40
field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8
+ field public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
field public static final int FLAG_CLEAR_TASK_ON_LAUNCH = 4; // 0x4
field public static final int FLAG_EXCLUDE_FROM_RECENTS = 32; // 0x20
field public static final int FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS = 256; // 0x100
@@ -7677,6 +7696,7 @@
field public static final int FLAG_IMMERSIVE = 2048; // 0x800
field public static final int FLAG_MULTIPROCESS = 1; // 0x1
field public static final int FLAG_NO_HISTORY = 128; // 0x80
+ field public static final int FLAG_PERSISTABLE = 4096; // 0x1000
field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
field public static final int FLAG_STATE_NOT_NEEDED = 16; // 0x10
field public static final int LAUNCH_MULTIPLE = 0; // 0x0
@@ -7701,6 +7721,7 @@
field public static final int SCREEN_ORIENTATION_USER_PORTRAIT = 12; // 0xc
field public static final int UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW = 1; // 0x1
field public int configChanges;
+ field public int documentLaunchMode;
field public int flags;
field public int launchMode;
field public java.lang.String parentActivityName;
@@ -8051,6 +8072,7 @@
field public static final java.lang.String FEATURE_SENSOR_BAROMETER = "android.hardware.sensor.barometer";
field public static final java.lang.String FEATURE_SENSOR_COMPASS = "android.hardware.sensor.compass";
field public static final java.lang.String FEATURE_SENSOR_GYROSCOPE = "android.hardware.sensor.gyroscope";
+ field public static final java.lang.String FEATURE_SENSOR_HEART_RATE = "android.hardware.sensor.heartrate";
field public static final java.lang.String FEATURE_SENSOR_LIGHT = "android.hardware.sensor.light";
field public static final java.lang.String FEATURE_SENSOR_PROXIMITY = "android.hardware.sensor.proximity";
field public static final java.lang.String FEATURE_SENSOR_STEP_COUNTER = "android.hardware.sensor.stepcounter";
@@ -11839,7 +11861,6 @@
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_WHITE_LEVEL;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_MAX_ANALOG_SENSITIVITY;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_ORIENTATION;
- field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_REFERENCE_ILLUMINANT1;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_REFERENCE_ILLUMINANT2;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
@@ -12221,8 +12242,6 @@
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FRAME_DURATION;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_GREEN_SPLIT;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_NEUTRAL_COLOR_POINT;
- field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_HUE_SAT_MAP;
- field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_TONE_CURVE;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEMPERATURE;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_DATA;
@@ -13559,6 +13578,7 @@
method public void stop() throws java.lang.IllegalStateException;
method public int write(byte[], int, int);
method public int write(short[], int, int);
+ method public int write(java.nio.ByteBuffer, int, int);
field public static final int ERROR = -1; // 0xffffffff
field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
field public static final int ERROR_INVALID_OPERATION = -3; // 0xfffffffd
@@ -13571,6 +13591,8 @@
field public static final int STATE_NO_STATIC_DATA = 2; // 0x2
field public static final int STATE_UNINITIALIZED = 0; // 0x0
field public static final int SUCCESS = 0; // 0x0
+ field public static final int WRITE_BLOCKING = 0; // 0x0
+ field public static final int WRITE_NON_BLOCKING = 1; // 0x1
}
public static abstract interface AudioTrack.OnPlaybackPositionUpdateListener {
@@ -15463,12 +15485,15 @@
method public void disconnect(android.media.session.RouteInfo);
method public android.media.session.SessionToken getSessionToken();
method public android.media.session.TransportPerformer getTransportPerformer();
- method public void publish();
+ method public boolean isActive();
method public void release();
method public void removeCallback(android.media.session.Session.Callback);
method public void sendEvent(java.lang.String, android.os.Bundle);
+ method public void setActive(boolean);
+ method public void setFlags(int);
method public void setRouteOptions(java.util.List<android.media.session.RouteOptions>);
- method public android.media.session.TransportPerformer setTransportPerformerEnabled();
+ field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+ field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
public static abstract class Session.Callback {
@@ -15507,7 +15532,7 @@
public final class SessionManager {
method public android.media.session.Session createSession(java.lang.String);
- method public java.util.List<android.media.session.SessionController> getActiveSessions();
+ method public java.util.List<android.media.session.SessionController> getActiveSessions(android.content.ComponentName);
}
public class SessionToken implements android.os.Parcelable {
@@ -15697,6 +15722,7 @@
method public android.net.NetworkInfo getActiveNetworkInfo();
method public android.net.NetworkInfo[] getAllNetworkInfo();
method public deprecated boolean getBackgroundDataSetting();
+ method public android.net.ProxyInfo getGlobalProxy();
method public android.net.NetworkInfo getNetworkInfo(int);
method public int getNetworkPreference();
method public boolean isActiveNetworkMetered();
@@ -15704,6 +15730,7 @@
method public static boolean isNetworkTypeValid(int);
method public void registerNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
method public boolean requestRouteToHost(int, int);
+ method public void setGlobalProxy(android.net.ProxyInfo);
method public void setNetworkPreference(int);
method public int startUsingNetworkFeature(int, java.lang.String);
method public int stopUsingNetworkFeature(int, java.lang.String);
@@ -15879,9 +15906,22 @@
method public static final deprecated int getDefaultPort();
method public static final deprecated java.lang.String getHost(android.content.Context);
method public static final deprecated int getPort(android.content.Context);
+ field public static final java.lang.String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
field public static final java.lang.String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
}
+ public class ProxyInfo implements android.os.Parcelable {
+ method public static android.net.ProxyInfo buildDirectProxy(java.lang.String, int);
+ method public static android.net.ProxyInfo buildDirectProxy(java.lang.String, int, java.util.List<java.lang.String>);
+ method public static android.net.ProxyInfo buildPacProxy(android.net.Uri);
+ method public int describeContents();
+ method public java.lang.String[] getExclusionList();
+ method public java.lang.String getHost();
+ method public android.net.Uri getPacFileUrl();
+ method public int getPort();
+ method public void writeToParcel(android.os.Parcel, int);
+ }
+
public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
ctor public deprecated SSLCertificateSocketFactory(int);
method public java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException;
@@ -20505,16 +20545,28 @@
method public void setUserRestriction(java.lang.String, boolean);
method public void setUserRestrictions(android.os.Bundle);
method public void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
+ field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
+ field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
+ field public static final java.lang.String DISALLOW_CONFIG_APPS = "no_config_apps";
field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
+ field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
+ field public static final java.lang.String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
+ field public static final java.lang.String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
+ field public static final java.lang.String DISALLOW_CONFIG_VPN = "no_config_vpn";
field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi";
+ field public static final java.lang.String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";
+ field public static final java.lang.String DISALLOW_FACTORY_RESET = "no_factory_reset";
field public static final java.lang.String DISALLOW_INSTALL_APPS = "no_install_apps";
field public static final java.lang.String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
field public static final java.lang.String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
+ field public static final java.lang.String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";
field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
+ field public static final java.lang.String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";
field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
+ field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
}
public abstract class Vibrator {
@@ -24537,6 +24589,7 @@
method public void contextDump();
method public static android.renderscript.RenderScript create(android.content.Context);
method public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType);
+ method public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType, long);
method public void destroy();
method public void finish();
method public final android.content.Context getApplicationContext();
@@ -24546,6 +24599,9 @@
method public void setErrorHandler(android.renderscript.RenderScript.RSErrorHandler);
method public void setMessageHandler(android.renderscript.RenderScript.RSMessageHandler);
method public void setPriority(android.renderscript.RenderScript.Priority);
+ field public static final long CREATE_FLAG_LOW_LATENCY = 1L; // 0x1L
+ field public static final long CREATE_FLAG_LOW_POWER = 2L; // 0x2L
+ field public static final long CREATE_FLAG_NONE = 0L; // 0x0L
}
public static final class RenderScript.ContextType extends java.lang.Enum {
@@ -25059,6 +25115,36 @@
}
+package android.service.fingerprint {
+
+ public class FingerprintManager {
+ ctor public FingerprintManager(android.content.Context);
+ method public void enroll(long);
+ method public void remove(int);
+ method public void startListening(android.service.fingerprint.FingerprintManagerReceiver);
+ method public void stopListening();
+ field protected static final boolean DEBUG = true;
+ field public static final int FINGERPRINT_ERROR = -1; // 0xffffffff
+ field public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2; // 0x2
+ field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
+ field public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10; // 0xfffffff6
+ field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
+ field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
+ field public static final int FINGERPRINT_SCANNED = 1; // 0x1
+ field public static final int FINGERPRINT_TEMPLATE_ENROLLING = 2; // 0x2
+ field public static final int FINGERPRINT_TEMPLATE_REMOVED = 4; // 0x4
+ }
+
+ public class FingerprintManagerReceiver {
+ ctor public FingerprintManagerReceiver();
+ method public void onEnrollResult(int, int);
+ method public void onError(int);
+ method public void onRemoved(int);
+ method public void onScanned(int, int);
+ }
+
+}
+
package android.service.notification {
public abstract class NotificationListenerService extends android.app.Service {
@@ -30476,6 +30562,7 @@
method public final int getScrollY();
method public java.lang.String getSharedElementName();
method public int getSolidColor();
+ method public android.animation.StateListAnimator getStateListAnimator();
method protected int getSuggestedMinimumHeight();
method protected int getSuggestedMinimumWidth();
method public int getSystemUiVisibility();
@@ -30740,6 +30827,7 @@
method public void setSelected(boolean);
method public void setSharedElementName(java.lang.String);
method public void setSoundEffectsEnabled(boolean);
+ method public void setStateListAnimator(android.animation.StateListAnimator);
method public void setSystemUiVisibility(int);
method public void setTag(java.lang.Object);
method public void setTag(int, java.lang.Object);
@@ -31596,26 +31684,17 @@
method public abstract void onFocusLost(android.view.WindowId);
}
- public class WindowInsets {
+ public final class WindowInsets {
ctor public WindowInsets(android.view.WindowInsets);
- method public android.view.WindowInsets cloneWithSystemWindowInsets(int, int, int, int);
- method public android.view.WindowInsets cloneWithSystemWindowInsetsConsumed();
- method public android.view.WindowInsets cloneWithSystemWindowInsetsConsumed(boolean, boolean, boolean, boolean);
- method public android.view.WindowInsets cloneWithWindowDecorInsets(int, int, int, int);
- method public android.view.WindowInsets cloneWithWindowDecorInsetsConsumed();
- method public android.view.WindowInsets cloneWithWindowDecorInsetsConsumed(boolean, boolean, boolean, boolean);
+ method public android.view.WindowInsets consumeSystemWindowInsets();
method public int getSystemWindowInsetBottom();
method public int getSystemWindowInsetLeft();
method public int getSystemWindowInsetRight();
method public int getSystemWindowInsetTop();
- method public int getWindowDecorInsetBottom();
- method public int getWindowDecorInsetLeft();
- method public int getWindowDecorInsetRight();
- method public int getWindowDecorInsetTop();
method public boolean hasInsets();
method public boolean hasSystemWindowInsets();
- method public boolean hasWindowDecorInsets();
method public boolean isRound();
+ method public android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int);
}
public abstract interface WindowManager implements android.view.ViewManager {
@@ -32942,6 +33021,16 @@
method public boolean hasMimeType(java.lang.String);
}
+ public abstract interface PermissionRequest {
+ method public abstract void deny();
+ method public abstract android.net.Uri getOrigin();
+ method public abstract long getResources();
+ method public abstract void grant(long);
+ field public static final long RESOURCE_AUDIO_CAPTURE = 4L; // 0x4L
+ field public static final long RESOURCE_GEOLOCATION = 1L; // 0x1L
+ field public static final long RESOURCE_VIDEO_CAPTURE = 2L; // 0x2L
+ }
+
public abstract interface PluginStub {
method public abstract android.view.View getEmbeddedView(int, android.content.Context);
method public abstract android.view.View getFullScreenView(int, android.content.Context);
@@ -33001,6 +33090,8 @@
method public boolean onJsConfirm(android.webkit.WebView, java.lang.String, java.lang.String, android.webkit.JsResult);
method public boolean onJsPrompt(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String, android.webkit.JsPromptResult);
method public deprecated boolean onJsTimeout();
+ method public void onPermissionRequest(android.webkit.PermissionRequest);
+ method public void onPermissionRequestCanceled(android.webkit.PermissionRequest);
method public void onProgressChanged(android.webkit.WebView, int);
method public deprecated void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
method public void onReceivedIcon(android.webkit.WebView, android.graphics.Bitmap);
@@ -33288,6 +33379,7 @@
method public boolean pageUp(boolean);
method public void pauseTimers();
method public void postUrl(java.lang.String, byte[]);
+ method public void preauthorizePermission(android.net.Uri, long);
method public void reload();
method public void removeJavascriptInterface(java.lang.String);
method public void requestFocusNodeHref(android.os.Message);
@@ -39740,11 +39832,13 @@
method public java.lang.String getValue();
method public int getVersion();
method public boolean hasExpired();
+ method public boolean isHttpOnly();
method public static java.util.List<java.net.HttpCookie> parse(java.lang.String);
method public void setComment(java.lang.String);
method public void setCommentURL(java.lang.String);
method public void setDiscard(boolean);
method public void setDomain(java.lang.String);
+ method public void setHttpOnly(boolean);
method public void setMaxAge(long);
method public void setPath(java.lang.String);
method public void setPortlist(java.lang.String);
@@ -40697,7 +40791,7 @@
ctor public ConnectionPendingException();
}
- public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel {
+ public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.MulticastChannel java.nio.channels.ScatteringByteChannel {
ctor protected DatagramChannel(java.nio.channels.spi.SelectorProvider);
method public java.nio.channels.DatagramChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.nio.channels.DatagramChannel connect(java.net.SocketAddress) throws java.io.IOException;
@@ -40705,6 +40799,8 @@
method public java.net.SocketAddress getLocalAddress() throws java.io.IOException;
method public T getOption(java.net.SocketOption<T>) throws java.io.IOException;
method public abstract boolean isConnected();
+ method public java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException;
+ method public java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException;
method public static java.nio.channels.DatagramChannel open() throws java.io.IOException;
method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
@@ -40752,6 +40848,7 @@
public abstract class FileLock implements java.lang.AutoCloseable {
ctor protected FileLock(java.nio.channels.FileChannel, long, long, boolean);
+ method public java.nio.channels.Channel acquiredBy();
method public final java.nio.channels.FileChannel channel();
method public final void close() throws java.io.IOException;
method public final boolean isShared();
@@ -40784,6 +40881,24 @@
method public abstract void close() throws java.io.IOException;
}
+ public abstract class MembershipKey {
+ ctor protected MembershipKey();
+ method public abstract java.nio.channels.MembershipKey block(java.net.InetAddress) throws java.io.IOException;
+ method public abstract java.nio.channels.MulticastChannel channel();
+ method public abstract void drop();
+ method public abstract java.net.InetAddress group();
+ method public abstract boolean isValid();
+ method public abstract java.net.NetworkInterface networkInterface();
+ method public abstract java.net.InetAddress sourceAddress();
+ method public abstract java.nio.channels.MembershipKey unblock(java.net.InetAddress);
+ }
+
+ public abstract interface MulticastChannel implements java.nio.channels.NetworkChannel {
+ method public abstract void close() throws java.io.IOException;
+ method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException;
+ method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException;
+ }
+
public abstract interface NetworkChannel implements java.lang.AutoCloseable java.nio.channels.Channel java.io.Closeable {
method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
@@ -44889,6 +45004,7 @@
method public java.lang.String getDisplayName(java.util.Locale);
method public static java.util.Currency getInstance(java.lang.String);
method public static java.util.Currency getInstance(java.util.Locale);
+ method public int getNumericCode();
method public java.lang.String getSymbol();
method public java.lang.String getSymbol(java.util.Locale);
}
@@ -47971,8 +48087,10 @@
public class ZipFile implements java.io.Closeable {
ctor public ZipFile(java.io.File) throws java.io.IOException, java.util.zip.ZipException;
+ ctor public ZipFile(java.io.File, java.nio.charset.Charset) throws java.io.IOException, java.util.zip.ZipException;
ctor public ZipFile(java.lang.String) throws java.io.IOException;
ctor public ZipFile(java.io.File, int) throws java.io.IOException;
+ ctor public ZipFile(java.io.File, int, java.nio.charset.Charset) throws java.io.IOException;
method public void close() throws java.io.IOException;
method public java.util.Enumeration<? extends java.util.zip.ZipEntry> entries();
method public java.lang.String getComment();
@@ -48026,6 +48144,7 @@
public class ZipInputStream extends java.util.zip.InflaterInputStream {
ctor public ZipInputStream(java.io.InputStream);
+ ctor public ZipInputStream(java.io.InputStream, java.nio.charset.Charset);
method public void closeEntry() throws java.io.IOException;
method protected java.util.zip.ZipEntry createZipEntry(java.lang.String);
method public java.util.zip.ZipEntry getNextEntry() throws java.io.IOException;
@@ -48073,6 +48192,7 @@
public class ZipOutputStream extends java.util.zip.DeflaterOutputStream {
ctor public ZipOutputStream(java.io.OutputStream);
+ ctor public ZipOutputStream(java.io.OutputStream, java.nio.charset.Charset);
method public void closeEntry() throws java.io.IOException;
method public void putNextEntry(java.util.zip.ZipEntry) throws java.io.IOException;
method public void setComment(java.lang.String);
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index 20236aa..933135d 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -21,6 +21,7 @@
import android.content.res.XmlResourceParser;
import android.content.res.Resources.NotFoundException;
import android.util.AttributeSet;
+import android.util.StateSet;
import android.util.TypedValue;
import android.util.Xml;
import android.view.animation.AnimationUtils;
@@ -87,9 +88,86 @@
}
}
+ public static StateListAnimator loadStateListAnimator(Context context, int id)
+ throws NotFoundException {
+ XmlResourceParser parser = null;
+ try {
+ parser = context.getResources().getAnimation(id);
+ return createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
+ } catch (XmlPullParserException ex) {
+ Resources.NotFoundException rnf =
+ new Resources.NotFoundException(
+ "Can't load state list animator resource ID #0x" +
+ Integer.toHexString(id)
+ );
+ rnf.initCause(ex);
+ throw rnf;
+ } catch (IOException ex) {
+ Resources.NotFoundException rnf =
+ new Resources.NotFoundException(
+ "Can't load state list animator resource ID #0x" +
+ Integer.toHexString(id)
+ );
+ rnf.initCause(ex);
+ throw rnf;
+ } finally {
+ if (parser != null) {
+ parser.close();
+ }
+ }
+ }
+
+ private static StateListAnimator createStateListAnimatorFromXml(Context context,
+ XmlPullParser parser, AttributeSet attributeSet)
+ throws IOException, XmlPullParserException {
+ int type;
+ StateListAnimator stateListAnimator = new StateListAnimator();
+
+ while (true) {
+ type = parser.next();
+ switch (type) {
+ case XmlPullParser.END_DOCUMENT:
+ case XmlPullParser.END_TAG:
+ return stateListAnimator;
+
+ case XmlPullParser.START_TAG:
+ // parse item
+ Animator animator = null;
+ if ("item".equals(parser.getName())) {
+ int attributeCount = parser.getAttributeCount();
+ int[] states = new int[attributeCount];
+ int stateIndex = 0;
+ for (int i = 0; i < attributeCount; i++) {
+ int attrName = attributeSet.getAttributeNameResource(i);
+ if (attrName == com.android.internal.R.attr.animation) {
+ animator = loadAnimator(context,
+ attributeSet.getAttributeResourceValue(i, 0));
+ } else {
+ states[stateIndex++] =
+ attributeSet.getAttributeBooleanValue(i, false) ?
+ attrName : -attrName;
+ }
+
+ }
+ if (animator == null) {
+ animator = createAnimatorFromXml(context, parser);
+ }
+
+ if (animator == null) {
+ throw new Resources.NotFoundException(
+ "animation state item must have a valid animation");
+ }
+ stateListAnimator
+ .addState(StateSet.trimStateSet(states, stateIndex), animator);
+
+ }
+ break;
+ }
+ }
+ }
+
private static Animator createAnimatorFromXml(Context c, XmlPullParser parser)
throws XmlPullParserException, IOException {
-
return createAnimatorFromXml(c, parser, Xml.asAttributeSet(parser), null, 0);
}
diff --git a/core/java/android/animation/StateListAnimator.java b/core/java/android/animation/StateListAnimator.java
new file mode 100644
index 0000000..bc4843d
--- /dev/null
+++ b/core/java/android/animation/StateListAnimator.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.animation;
+
+import android.util.StateSet;
+import android.view.View;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+/**
+ * Lets you define a number of Animators that will run on the attached View depending on the View's
+ * drawable state.
+ * <p>
+ * It can be defined in an XML file with the <code><selector></code> element.
+ * Each State Animator is defined in a nested <code><item></code> element.
+ *
+ * @attr ref android.R.styleable#DrawableStates_state_focused
+ * @attr ref android.R.styleable#DrawableStates_state_window_focused
+ * @attr ref android.R.styleable#DrawableStates_state_enabled
+ * @attr ref android.R.styleable#DrawableStates_state_checkable
+ * @attr ref android.R.styleable#DrawableStates_state_checked
+ * @attr ref android.R.styleable#DrawableStates_state_selected
+ * @attr ref android.R.styleable#DrawableStates_state_activated
+ * @attr ref android.R.styleable#DrawableStates_state_active
+ * @attr ref android.R.styleable#DrawableStates_state_single
+ * @attr ref android.R.styleable#DrawableStates_state_first
+ * @attr ref android.R.styleable#DrawableStates_state_middle
+ * @attr ref android.R.styleable#DrawableStates_state_last
+ * @attr ref android.R.styleable#DrawableStates_state_pressed
+ * @attr ref android.R.styleable#StateListAnimatorItem_animation
+ */
+public class StateListAnimator {
+
+ private final ArrayList<Tuple> mTuples = new ArrayList<Tuple>();
+
+ private Tuple mLastMatch = null;
+
+ private Animator mRunningAnimator = null;
+
+ private WeakReference<View> mViewRef;
+
+ private AnimatorListenerAdapter mAnimatorListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mRunningAnimator == animation) {
+ mRunningAnimator = null;
+ }
+ }
+ };
+
+ /**
+ * Associates the given animator with the provided drawable state specs so that it will be run
+ * when the View's drawable state matches the specs.
+ *
+ * @param specs The drawable state specs to match against
+ * @param animator The animator to run when the specs match
+ */
+ public void addState(int[] specs, Animator animator) {
+ Tuple tuple = new Tuple(specs, animator);
+ tuple.mAnimator.addListener(mAnimatorListener);
+ mTuples.add(tuple);
+ }
+
+ /**
+ * Returns the current {@link android.animation.Animator} which is started because of a state
+ * change.
+ *
+ * @return The currently running Animator or null if no Animator is running
+ * @hide
+ */
+ public Animator getRunningAnimator() {
+ return mRunningAnimator;
+ }
+
+ /**
+ * @hide
+ */
+ public View getTarget() {
+ return mViewRef == null ? null : mViewRef.get();
+ }
+
+ /**
+ * Called by View
+ * @hide
+ */
+ public void setTarget(View view) {
+ final View current = getTarget();
+ if (current == view) {
+ return;
+ }
+ if (current != null) {
+ clearTarget();
+ }
+ if (view != null) {
+ mViewRef = new WeakReference<View>(view);
+ }
+
+ }
+
+ private void clearTarget() {
+ final int size = mTuples.size();
+ for (int i = 0; i < size; i++) {
+ mTuples.get(i).mAnimator.setTarget(null);
+ }
+
+ mViewRef = null;
+ mLastMatch = null;
+ mRunningAnimator = null;
+ }
+
+ /**
+ * Called by View
+ * @hide
+ */
+ public void setState(int[] state) {
+ Tuple match = null;
+ final int count = mTuples.size();
+ for (int i = 0; i < count; i++) {
+ final Tuple tuple = mTuples.get(i);
+ if (StateSet.stateSetMatches(tuple.mSpecs, state)) {
+ match = tuple;
+ break;
+ }
+ }
+ if (match == mLastMatch) {
+ return;
+ }
+ if (mLastMatch != null) {
+ cancel(mLastMatch);
+ }
+ mLastMatch = match;
+ if (match != null) {
+ start(match);
+ }
+ }
+
+ private void start(Tuple match) {
+ match.mAnimator.setTarget(getTarget());
+ mRunningAnimator = match.mAnimator;
+ match.mAnimator.start();
+ }
+
+ private void cancel(Tuple lastMatch) {
+ lastMatch.mAnimator.cancel();
+ lastMatch.mAnimator.setTarget(null);
+ }
+
+ /**
+ * @hide
+ */
+ public ArrayList<Tuple> getTuples() {
+ return mTuples;
+ }
+
+ /**
+ * If there is an animation running for a recent state change, ends it.
+ * <p>
+ * This causes the animation to assign the end value(s) to the View.
+ */
+ public void jumpToCurrentState() {
+ if (mRunningAnimator != null) {
+ mRunningAnimator.end();
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static class Tuple {
+
+ final int[] mSpecs;
+
+ final Animator mAnimator;
+
+ private Tuple(int[] specs, Animator animator) {
+ mSpecs = specs;
+ mAnimator = animator;
+ }
+
+ /**
+ * @hide
+ */
+ public int[] getSpecs() {
+ return mSpecs;
+ }
+
+ /**
+ * @hide
+ */
+ public Animator getAnimator() {
+ return mAnimator;
+ }
+ }
+}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index af3a92c..36f9f4b 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -29,6 +29,7 @@
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.app.admin.DevicePolicyManager;
import android.content.ComponentCallbacks2;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -5689,7 +5690,16 @@
}
}
- /** @hide */
+ /**
+ * Put this Activity in a mode where the user is locked to the
+ * current task.
+ *
+ * This will prevent the user from launching other apps, going to settings,
+ * or reaching the home screen.
+ *
+ * Lock task mode will only start if the activity has been whitelisted by the
+ * Device Owner through DevicePolicyManager#setLockTaskComponents.
+ */
public void startLockTask() {
try {
ActivityManagerNative.getDefault().startLockTaskMode(mToken);
@@ -5697,7 +5707,15 @@
}
}
- /** @hide */
+ /**
+ * Allow the user to switch away from the current task.
+ *
+ * Called to end the mode started by {@link Activity#startLockTask}. This
+ * can only be called by activities that have successfully called
+ * startLockTask previously.
+ *
+ * This will allow the user to exit this app and move onto other activities.
+ */
public void stopLockTask() {
try {
ActivityManagerNative.getDefault().stopLockTaskMode();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 3b2ff7f..b606088 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -46,7 +46,7 @@
import android.hardware.display.DisplayManagerGlobal;
import android.net.IConnectivityManager;
import android.net.Proxy;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
import android.opengl.GLUtils;
import android.os.AsyncTask;
import android.os.Binder;
@@ -4294,8 +4294,8 @@
// crash if we can't get it.
IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
try {
- ProxyProperties proxyProperties = service.getProxy();
- Proxy.setHttpProxySystemProperty(proxyProperties);
+ ProxyInfo proxyInfo = service.getProxy();
+ Proxy.setHttpProxySystemProperty(proxyInfo);
} catch (RemoteException e) {}
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index fe532bf..5ed5030 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -16,6 +16,8 @@
package android.app;
+import android.net.wifi.IWifiScanner;
+import android.net.wifi.WifiScanner;
import android.os.Build;
import com.android.internal.policy.PolicyManager;
@@ -106,6 +108,9 @@
import android.os.storage.StorageManager;
import android.print.IPrintManager;
import android.print.PrintManager;
+import android.service.fingerprint.FingerprintManager;
+import android.service.fingerprint.FingerprintManagerReceiver;
+import android.service.fingerprint.FingerprintService;
import android.telephony.TelephonyManager;
import android.tv.ITvInputManager;
import android.tv.TvInputManager;
@@ -451,6 +456,11 @@
return new KeyguardManager();
}});
+ registerService(FINGERPRINT_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return new FingerprintManager(ctx);
+ }});
+
registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
@@ -581,6 +591,13 @@
return new WifiP2pManager(service);
}});
+ registerService(WIFI_SCANNING_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(WIFI_SCANNING_SERVICE);
+ IWifiScanner service = IWifiScanner.Stub.asInterface(b);
+ return new WifiScanner(ctx.getOuterContext(), service);
+ }});
+
registerService(WINDOW_SERVICE, new ServiceFetcher() {
Display mDefaultDisplay;
public Object getService(ContextImpl ctx) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 25a1493..bba6caf 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -17,7 +17,7 @@
package android.app;
import com.android.internal.R;
-import com.android.internal.util.LegacyNotificationUtil;
+import com.android.internal.util.NotificationColorUtil;
import android.annotation.IntDef;
import android.content.Context;
@@ -28,6 +28,7 @@
import android.media.AudioManager;
import android.net.Uri;
import android.os.BadParcelableException;
+import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -420,6 +421,21 @@
@Priority
public int priority;
+ /**
+ * Accent color (an ARGB integer like the constants in {@link android.graphics.Color})
+ * to be applied by the standard Style templates when presenting this notification.
+ *
+ * The current template design constructs a colorful header image by overlaying the
+ * {@link #icon} image (stenciled in white) atop a field of this color. Alpha components are
+ * ignored.
+ */
+ public int color = COLOR_DEFAULT;
+
+ /**
+ * Special value of {@link #color} telling the system not to decorate this notification with
+ * any special color but instead use default colors when presenting this notification.
+ */
+ public static final int COLOR_DEFAULT = 0; // AKA Color.TRANSPARENT
/**
* Sphere of visibility of this notification, which affects how and when the SystemUI reveals
@@ -877,6 +893,8 @@
if (parcel.readInt() != 0) {
publicVersion = Notification.CREATOR.createFromParcel(parcel);
}
+
+ color = parcel.readInt();
}
@Override
@@ -968,6 +986,8 @@
this.publicVersion.cloneInto(that.publicVersion, heavy);
}
+ that.color = this.color;
+
if (!heavy) {
that.lightenPayload(); // will clean out extras
}
@@ -1110,6 +1130,8 @@
} else {
parcel.writeInt(0);
}
+
+ parcel.writeInt(color);
}
/**
@@ -1218,6 +1240,7 @@
sb.append(Integer.toHexString(this.defaults));
sb.append(" flags=0x");
sb.append(Integer.toHexString(this.flags));
+ sb.append(String.format(" color=0x%08x", this.color));
sb.append(" category="); sb.append(this.category);
if (actions != null) {
sb.append(" ");
@@ -1309,9 +1332,10 @@
private boolean mShowWhen = true;
private int mVisibility = VISIBILITY_PRIVATE;
private Notification mPublicVersion = null;
- private boolean mQuantumTheme;
- private final LegacyNotificationUtil mLegacyNotificationUtil;
+ private final NotificationColorUtil mColorUtil;
private ArrayList<String> mPeople;
+ private boolean mPreQuantum;
+ private int mColor = COLOR_DEFAULT;
/**
* Constructs a new Builder with the defaults:
@@ -1341,12 +1365,8 @@
mPriority = PRIORITY_DEFAULT;
mPeople = new ArrayList<String>();
- // TODO: Decide on targetSdk from calling app whether to use quantum theme.
- mQuantumTheme = true;
-
- // TODO: Decide on targetSdk from calling app whether to instantiate the processor at
- // all.
- mLegacyNotificationUtil = LegacyNotificationUtil.getInstance();
+ mPreQuantum = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.L;
+ mColorUtil = NotificationColorUtil.getInstance();
}
/**
@@ -1853,29 +1873,38 @@
}
}
+ /**
+ * Sets {@link Notification#color}.
+ *
+ * @param argb The accent color to use
+ *
+ * @return The same Builder.
+ */
+ public Builder setColor(int argb) {
+ mColor = argb;
+ return this;
+ }
+
private RemoteViews applyStandardTemplate(int resId, boolean fitIn1U) {
RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
boolean showLine3 = false;
boolean showLine2 = false;
int smallIconImageViewId = R.id.icon;
- if (!mQuantumTheme && mPriority < PRIORITY_LOW) {
- contentView.setInt(R.id.icon,
- "setBackgroundResource", R.drawable.notification_template_icon_low_bg);
- contentView.setInt(R.id.status_bar_latest_event_content,
- "setBackgroundResource", R.drawable.notification_bg_low);
+ if (mPriority < PRIORITY_LOW) {
+ // TODO: Low priority presentation
}
if (mLargeIcon != null) {
contentView.setImageViewBitmap(R.id.icon, mLargeIcon);
- processLegacyLargeIcon(mLargeIcon, contentView);
+ processLargeIcon(mLargeIcon, contentView);
smallIconImageViewId = R.id.right_icon;
}
if (mSmallIcon != 0) {
contentView.setImageViewResource(smallIconImageViewId, mSmallIcon);
contentView.setViewVisibility(smallIconImageViewId, View.VISIBLE);
if (mLargeIcon != null) {
- processLegacySmallIcon(mSmallIcon, smallIconImageViewId, contentView);
+ processSmallRightIcon(mSmallIcon, smallIconImageViewId, contentView);
} else {
- processLegacyLargeIcon(mSmallIcon, contentView);
+ processSmallIconAsLarge(mSmallIcon, contentView);
}
} else {
@@ -2035,12 +2064,12 @@
* doesn't create quantum notifications by itself) app.
*/
private boolean isLegacy() {
- return mLegacyNotificationUtil != null;
+ return mColorUtil != null;
}
private void processLegacyAction(Action action, RemoteViews button) {
if (isLegacy()) {
- if (mLegacyNotificationUtil.isGrayscale(mContext, action.icon)) {
+ if (mColorUtil.isGrayscale(mContext, action.icon)) {
button.setTextViewCompoundDrawablesRelativeColorFilter(R.id.action0, 0,
mContext.getResources().getColor(
R.color.notification_action_legacy_color_filter),
@@ -2051,47 +2080,70 @@
private CharSequence processLegacyText(CharSequence charSequence) {
if (isLegacy()) {
- return mLegacyNotificationUtil.invertCharSequenceColors(charSequence);
+ return mColorUtil.invertCharSequenceColors(charSequence);
} else {
return charSequence;
}
}
- private void processLegacyLargeIcon(int largeIconId, RemoteViews contentView) {
- if (isLegacy()) {
- processLegacyLargeIcon(
- mLegacyNotificationUtil.isGrayscale(mContext, largeIconId),
- contentView);
+ /**
+ * Apply any necessary background to smallIcons being used in the largeIcon spot.
+ */
+ private void processSmallIconAsLarge(int largeIconId, RemoteViews contentView) {
+ if (!isLegacy() || mColorUtil.isGrayscale(mContext, largeIconId)) {
+ applyLargeIconBackground(contentView);
}
}
- private void processLegacyLargeIcon(Bitmap largeIcon, RemoteViews contentView) {
- if (isLegacy()) {
- processLegacyLargeIcon(
- mLegacyNotificationUtil.isGrayscale(largeIcon),
- contentView);
+ /**
+ * Apply any necessary background to a largeIcon if it's a fake smallIcon (that is,
+ * if it's grayscale).
+ */
+ // TODO: also check bounds, transparency, that sort of thing.
+ private void processLargeIcon(Bitmap largeIcon, RemoteViews contentView) {
+ if (!isLegacy() || mColorUtil.isGrayscale(largeIcon)) {
+ applyLargeIconBackground(contentView);
}
}
- private void processLegacyLargeIcon(boolean isGrayscale, RemoteViews contentView) {
- if (isLegacy() && isGrayscale) {
- contentView.setInt(R.id.icon, "setBackgroundResource",
- R.drawable.notification_icon_legacy_bg_inset);
- }
+ /**
+ * Add a colored circle behind the largeIcon slot.
+ */
+ private void applyLargeIconBackground(RemoteViews contentView) {
+ contentView.setInt(R.id.icon, "setBackgroundResource",
+ R.drawable.notification_icon_legacy_bg_inset);
+
+ contentView.setDrawableParameters(
+ R.id.icon,
+ true,
+ -1,
+ mColor,
+ PorterDuff.Mode.SRC_ATOP,
+ -1);
}
- private void processLegacySmallIcon(int smallIconDrawableId, int smallIconImageViewId,
+ /**
+ * Recolor small icons when used in the R.id.right_icon slot.
+ */
+ private void processSmallRightIcon(int smallIconDrawableId, int smallIconImageViewId,
RemoteViews contentView) {
- if (isLegacy()) {
- if (mLegacyNotificationUtil.isGrayscale(mContext, smallIconDrawableId)) {
- contentView.setDrawableParameters(smallIconImageViewId, false, -1,
- mContext.getResources().getColor(
- R.color.notification_action_legacy_color_filter),
- PorterDuff.Mode.MULTIPLY, -1);
- }
+ if (!isLegacy() || mColorUtil.isGrayscale(mContext, smallIconDrawableId)) {
+ contentView.setDrawableParameters(smallIconImageViewId, false, -1,
+ mContext.getResources().getColor(
+ R.color.notification_action_legacy_color_filter),
+ PorterDuff.Mode.MULTIPLY, -1);
}
}
+ private int resolveColor() {
+ if (mColor == COLOR_DEFAULT) {
+ mColor = mContext.getResources().getColor(R.color.notification_icon_bg_color);
+ } else {
+ mColor |= 0xFF000000; // no alpha for custom colors
+ }
+ return mColor;
+ }
+
/**
* Apply the unstyled operations and return a new {@link Notification} object.
* @hide
@@ -2102,6 +2154,9 @@
n.icon = mSmallIcon;
n.iconLevel = mSmallIconLevel;
n.number = mNumber;
+
+ n.color = resolveColor();
+
n.contentView = makeContentView();
n.contentIntent = mContentIntent;
n.deleteIntent = mDeleteIntent;
@@ -2207,45 +2262,31 @@
private int getBaseLayoutResource() {
- return mQuantumTheme
- ? R.layout.notification_template_quantum_base
- : R.layout.notification_template_base;
+ return R.layout.notification_template_quantum_base;
}
private int getBigBaseLayoutResource() {
- return mQuantumTheme
- ? R.layout.notification_template_quantum_big_base
- : R.layout.notification_template_big_base;
+ return R.layout.notification_template_quantum_big_base;
}
private int getBigPictureLayoutResource() {
- return mQuantumTheme
- ? R.layout.notification_template_quantum_big_picture
- : R.layout.notification_template_big_picture;
+ return R.layout.notification_template_quantum_big_picture;
}
private int getBigTextLayoutResource() {
- return mQuantumTheme
- ? R.layout.notification_template_quantum_big_text
- : R.layout.notification_template_big_text;
+ return R.layout.notification_template_quantum_big_text;
}
private int getInboxLayoutResource() {
- return mQuantumTheme
- ? R.layout.notification_template_quantum_inbox
- : R.layout.notification_template_inbox;
+ return R.layout.notification_template_quantum_inbox;
}
private int getActionLayoutResource() {
- return mQuantumTheme
- ? R.layout.notification_quantum_action
- : R.layout.notification_action;
+ return R.layout.notification_quantum_action;
}
private int getActionTombstoneLayoutResource() {
- return mQuantumTheme
- ? R.layout.notification_quantum_action_tombstone
- : R.layout.notification_action_tombstone;
+ return R.layout.notification_quantum_action_tombstone;
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 929bf65..61ff60a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -22,6 +22,7 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
@@ -2041,4 +2042,87 @@
}
}
}
+
+ /**
+ * Called by profile or device owner to re-enable a system app that was disabled by default
+ * when the managed profile was created. This should only be called from a profile or device
+ * owner running within a managed profile.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param packageName The package to be re-enabled in the current profile.
+ */
+ public void enableSystemApp(ComponentName admin, String packageName) {
+ if (mService != null) {
+ try {
+ mService.enableSystemApp(admin, packageName);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to install package: " + packageName);
+ }
+ }
+ }
+
+ /**
+ * Called by a profile owner to disable account management for a specific type of account.
+ *
+ * <p>The calling device admin must be a profile owner. If it is not, a
+ * security exception will be thrown.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param accountType For which account management is disabled or enabled.
+ * @param disabled The boolean indicating that account management will be disabled (true) or
+ * enabled (false).
+ */
+ public void setAccountManagementDisabled(ComponentName admin, String accountType,
+ boolean disabled) {
+ if (mService != null) {
+ try {
+ mService.setAccountManagementDisabled(admin, accountType, disabled);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * Called by profile or device owner to re-enable system apps by intent that were disabled
+ * by default when the managed profile was created. This should only be called from a profile
+ * or device owner running within a managed profile.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param intent An intent matching the app(s) to be installed. All apps that resolve for this
+ * intent will be re-enabled in the current profile.
+ * @return int The number of activities that matched the intent and were installed.
+ */
+ public int enableSystemApp(ComponentName admin, Intent intent) {
+ if (mService != null) {
+ try {
+ return mService.enableSystemAppWithIntent(admin, intent);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to install packages matching filter: " + intent);
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Gets the array of accounts for which account management is disabled by the profile owner.
+ *
+ * <p> Account management can be disabled/enabled by calling
+ * {@link #setAccountManagementDisabled}.
+ *
+ * @return a list of account types for which account management has been disabled.
+ *
+ * @see #setAccountManagementDisabled
+ */
+ public String[] getAccountTypesWithManagementDisabled() {
+ if (mService != null) {
+ try {
+ return mService.getAccountTypesWithManagementDisabled();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+
+ return null;
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index e3090b6..0096580 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -18,6 +18,7 @@
package android.app.admin;
import android.content.ComponentName;
+import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.RemoteCallback;
@@ -122,4 +123,10 @@
void setUserRestriction(in ComponentName who, in String key, boolean enable);
void addForwardingIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
void clearForwardingIntentFilters(in ComponentName admin);
+
+ void enableSystemApp(in ComponentName admin, in String packageName);
+ int enableSystemAppWithIntent(in ComponentName admin, in Intent intent);
+
+ void setAccountManagementDisabled(in ComponentName who, in String accountType, in boolean disabled);
+ String[] getAccountTypesWithManagementDisabled();
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index a396a05..7f8d0ab 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -512,6 +512,25 @@
*/
public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
+ /**
+ * No preferrence of physical transport for GATT connections to remote dual-mode devices
+ * @hide
+ */
+ public static final int TRANSPORT_AUTO = 0;
+
+ /**
+ * Prefer BR/EDR transport for GATT connections to remote dual-mode devices
+ * @hide
+ */
+ public static final int TRANSPORT_BREDR = 1;
+
+ /**
+ * Prefer LE transport for GATT connections to remote dual-mode devices
+ * @hide
+ */
+ public static final int TRANSPORT_LE = 2;
+
+
/**
* Lazy initialization. Guaranteed final after first object constructed, or
* getService() called.
@@ -1216,6 +1235,27 @@
*/
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback) {
+ return (connectGatt(context, autoConnect,callback, TRANSPORT_AUTO));
+ }
+
+ /**
+ * Connect to GATT Server hosted by this device. Caller acts as GATT client.
+ * The callback is used to deliver results to Caller, such as connection status as well
+ * as any further GATT client operations.
+ * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
+ * GATT client operations.
+ * @param callback GATT callback handler that will receive asynchronous callbacks.
+ * @param autoConnect Whether to directly connect to the remote device (false)
+ * or to automatically connect as soon as the remote
+ * device becomes available (true).
+ * @param transport preferred transport for GATT connections to remote dual-mode devices
+ * {@link BluetoothDevice#TRANSPORT_AUTO} or
+ * {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE}
+ * @throws IllegalArgumentException if callback is null
+ * @hide
+ */
+ public BluetoothGatt connectGatt(Context context, boolean autoConnect,
+ BluetoothGattCallback callback, int transport) {
// TODO(Bluetooth) check whether platform support BLE
// Do the check here or in GattServer?
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -1226,10 +1266,11 @@
// BLE is not supported
return null;
}
- BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this);
+ BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this, transport);
gatt.connect(autoConnect, callback);
return gatt;
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
+
}
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index ff3af7c..601d9ee 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -51,6 +51,7 @@
private int mConnState;
private final Object mStateLock = new Object();
private Boolean mDeviceBusy = false;
+ private int mTransport;
private static final int CONN_STATE_IDLE = 0;
private static final int CONN_STATE_CONNECTING = 1;
@@ -135,7 +136,7 @@
}
try {
mService.clientConnect(mClientIf, mDevice.getAddress(),
- !mAutoConnect); // autoConnect is inverse of "isDirect"
+ !mAutoConnect, mTransport); // autoConnect is inverse of "isDirect"
} catch (RemoteException e) {
Log.e(TAG,"",e);
}
@@ -600,10 +601,12 @@
}
};
- /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device) {
+ /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device,
+ int transport) {
mContext = context;
mService = iGatt;
mDevice = device;
+ mTransport = transport;
mServices = new ArrayList<BluetoothGattService>();
mConnState = CONN_STATE_IDLE;
@@ -759,7 +762,7 @@
public boolean connect() {
try {
mService.clientConnect(mClientIf, mDevice.getAddress(),
- false); // autoConnect is inverse of "isDirect"
+ false, mTransport); // autoConnect is inverse of "isDirect"
return true;
} catch (RemoteException e) {
Log.e(TAG,"",e);
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 0c00c06..34e8605 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -50,6 +50,7 @@
private Object mServerIfLock = new Object();
private int mServerIf;
+ private int mTransport;
private List<BluetoothGattService> mServices;
private static final int CALLBACK_REG_TIMEOUT = 10000;
@@ -269,12 +270,13 @@
/**
* Create a BluetoothGattServer proxy object.
*/
- /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt) {
+ /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt, int transport) {
mContext = context;
mService = iGatt;
mAdapter = BluetoothAdapter.getDefaultAdapter();
mCallback = null;
mServerIf = 0;
+ mTransport = transport;
mServices = new ArrayList<BluetoothGattService>();
}
@@ -401,7 +403,7 @@
try {
mService.serverConnect(mServerIf, device.getAddress(),
- autoConnect ? false : true); // autoConnect is inverse of "isDirect"
+ autoConnect ? false : true,mTransport); // autoConnect is inverse of "isDirect"
} catch (RemoteException e) {
Log.e(TAG,"",e);
return false;
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index 172f3bc..b1618cf3 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -194,6 +194,26 @@
*/
public BluetoothGattServer openGattServer(Context context,
BluetoothGattServerCallback callback) {
+
+ return (openGattServer (context, callback, BluetoothDevice.TRANSPORT_AUTO));
+ }
+
+ /**
+ * Open a GATT Server
+ * The callback is used to deliver results to Caller, such as connection status as well
+ * as the results of any other GATT server operations.
+ * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer
+ * to conduct GATT server operations.
+ * @param context App context
+ * @param callback GATT server callback handler that will receive asynchronous callbacks.
+ * @param transport preferred transport for GATT connections to remote dual-mode devices
+ * {@link BluetoothDevice#TRANSPORT_AUTO} or
+ * {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE}
+ * @return BluetoothGattServer instance
+ * @hide
+ */
+ public BluetoothGattServer openGattServer(Context context,
+ BluetoothGattServerCallback callback,int transport) {
if (context == null || callback == null) {
throw new IllegalArgumentException("null parameter: " + context + " " + callback);
}
@@ -208,7 +228,7 @@
Log.e(TAG, "Fail to get GATT Server connection");
return null;
}
- BluetoothGattServer mGattServer = new BluetoothGattServer(context, iGatt);
+ BluetoothGattServer mGattServer = new BluetoothGattServer(context, iGatt,transport);
Boolean regStatus = mGattServer.registerCallback(callback);
return regStatus? mGattServer : null;
} catch (RemoteException e) {
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index f532f7c..00fd7ce 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -325,6 +325,7 @@
}
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ throw new IOException("unable to send RPC: " + e.getMessage());
}
}
diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
index 6dd551e..a0b603e 100644
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
@@ -53,6 +53,9 @@
private static final boolean DBG = true;
private static final boolean VDBG = true;
+ // Event sent to the mBtdtHandler when DHCP fails so we can tear down the network.
+ private static final int EVENT_NETWORK_FAILED = 1;
+
private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
@@ -315,6 +318,7 @@
}
if (!success) {
Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
+ mBtdtHandler.obtainMessage(EVENT_NETWORK_FAILED).sendToTarget();
return;
}
mLinkProperties = dhcpResults.linkProperties;
@@ -407,6 +411,10 @@
if (VDBG) Log.d(TAG, "got EVENT_NETWORK_DISCONNECTED, " + linkProperties);
mBtdt.stopReverseTether();
break;
+ case EVENT_NETWORK_FAILED:
+ if (VDBG) Log.d(TAG, "got EVENT_NETWORK_FAILED");
+ mBtdt.teardown();
+ break;
}
}
}
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 4b28516..ab53fb0 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -18,6 +18,8 @@
import android.os.ParcelUuid;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.HashSet;
import java.util.UUID;
@@ -76,6 +78,12 @@
public static final ParcelUuid BASE_UUID =
ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
+ /** Length of bytes for 16 bit UUID */
+ public static final int UUID_BYTES_16_BIT = 2;
+ /** Length of bytes for 32 bit UUID */
+ public static final int UUID_BYTES_32_BIT = 4;
+ /** Length of bytes for 128 bit UUID */
+ public static final int UUID_BYTES_128_BIT = 16;
public static final ParcelUuid[] RESERVED_UUIDS = {
AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
@@ -216,15 +224,60 @@
}
/**
+ * Parse UUID from bytes. The {@code uuidBytes} can represent a 16-bit, 32-bit or 128-bit UUID,
+ * but the returned UUID is always in 128-bit format.
+ * Note UUID is little endian in Bluetooth.
+ *
+ * @param uuidBytes Byte representation of uuid.
+ * @return {@link ParcelUuid} parsed from bytes.
+ * @throws IllegalArgumentException If the {@code uuidBytes} cannot be parsed.
+ */
+ public static ParcelUuid parseUuidFrom(byte[] uuidBytes) {
+ if (uuidBytes == null) {
+ throw new IllegalArgumentException("uuidBytes cannot be null");
+ }
+ int length = uuidBytes.length;
+ if (length != UUID_BYTES_16_BIT && length != UUID_BYTES_32_BIT &&
+ length != UUID_BYTES_128_BIT) {
+ throw new IllegalArgumentException("uuidBytes length invalid - " + length);
+ }
+
+ // Construct a 128 bit UUID.
+ if (length == UUID_BYTES_128_BIT) {
+ ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN);
+ long msb = buf.getLong(8);
+ long lsb = buf.getLong(0);
+ return new ParcelUuid(new UUID(msb, lsb));
+ }
+
+ // For 16 bit and 32 bit UUID we need to convert them to 128 bit value.
+ // 128_bit_value = uuid * 2^96 + BASE_UUID
+ long shortUuid;
+ if (length == UUID_BYTES_16_BIT) {
+ shortUuid = uuidBytes[0] & 0xFF;
+ shortUuid += (uuidBytes[1] & 0xFF) << 8;
+ } else {
+ shortUuid = uuidBytes[0] & 0xFF ;
+ shortUuid += (uuidBytes[1] & 0xFF) << 8;
+ shortUuid += (uuidBytes[2] & 0xFF) << 16;
+ shortUuid += (uuidBytes[3] & 0xFF) << 24;
+ }
+ long msb = BASE_UUID.getUuid().getMostSignificantBits() + (shortUuid << 32);
+ long lsb = BASE_UUID.getUuid().getLeastSignificantBits();
+ return new ParcelUuid(new UUID(msb, lsb));
+ }
+
+ /**
* Check whether the given parcelUuid can be converted to 16 bit bluetooth uuid.
+ *
* @param parcelUuid
* @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise.
*/
public static boolean isShortUuid(ParcelUuid parcelUuid) {
- UUID uuid = parcelUuid.getUuid();
- if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
- return false;
- }
- return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L);
+ UUID uuid = parcelUuid.getUuid();
+ if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
+ return false;
+ }
+ return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L);
}
}
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index c6b5c3d..49b156d 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -35,7 +35,7 @@
void registerClient(in ParcelUuid appId, in IBluetoothGattCallback callback);
void unregisterClient(in int clientIf);
- void clientConnect(in int clientIf, in String address, in boolean isDirect);
+ void clientConnect(in int clientIf, in String address, in boolean isDirect, in int transport);
void clientDisconnect(in int clientIf, in String address);
void startAdvertising(in int appIf);
void stopAdvertising();
@@ -77,7 +77,7 @@
void registerServer(in ParcelUuid appId, in IBluetoothGattServerCallback callback);
void unregisterServer(in int serverIf);
- void serverConnect(in int servertIf, in String address, in boolean isDirect);
+ void serverConnect(in int servertIf, in String address, in boolean isDirect, in int transport);
void serverDisconnect(in int serverIf, in String address);
void beginServiceDeclaration(in int serverIf, in int srvcType,
in int srvcInstanceId, in int minHandles,
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index de223a3..042ee28 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1982,6 +1982,7 @@
WIFI_SERVICE,
WIFI_HOTSPOT_SERVICE,
WIFI_P2P_SERVICE,
+ WIFI_SCANNING_SERVICE,
NSD_SERVICE,
AUDIO_SERVICE,
MEDIA_ROUTER_SERVICE,
@@ -2054,6 +2055,9 @@
* <dt> {@link #WIFI_SERVICE} ("wifi")
* <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of
* Wi-Fi connectivity.
+ * <dt> {@link #WIFI_P2P_SERVICE} ("wifip2p")
+ * <dd> A {@link android.net.wifi.p2p.WifiP2pManager WifiP2pManager} for management of
+ * Wi-Fi Direct connectivity.
* <dt> {@link #INPUT_METHOD_SERVICE} ("input_method")
* <dd> An {@link android.view.inputmethod.InputMethodManager InputMethodManager}
* for management of input methods.
@@ -2357,6 +2361,16 @@
/**
* Use with {@link #getSystemService} to retrieve a {@link
+ * android.net.wifi.WifiScanner} for scanning the wifi universe
+ *
+ * @see #getSystemService
+ * @see android.net.wifi.WifiScanner
+ * @hide
+ */
+ public static final String WIFI_SCANNING_SERVICE = "wifiscanner";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a {@link
* android.net.nsd.NsdManager} for handling management of network service
* discovery
*
@@ -2377,6 +2391,16 @@
/**
* Use with {@link #getSystemService} to retrieve a
+ * {@link android.service.fingerprint.FingerprintManager} for handling management
+ * of fingerprints.
+ *
+ * @see #getSystemService
+ * @see android.app.FingerprintManager
+ */
+ public static final String FINGERPRINT_SERVICE = "fingerprint";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a
* {@link android.media.MediaRouter} for controlling and managing
* routing of media.
*
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index ae5437b..3cfc56c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3736,7 +3736,8 @@
*
* <p>When set, the activity specified by this Intent will launch into a
* separate task rooted at that activity. The activity launched must be
- * defined with {@link android.R.attr#launchMode} "standard" or "singleTop".
+ * defined with {@link android.R.attr#launchMode} <code>standard</code>
+ * or <code>singleTop</code>.
*
* <p>If FLAG_ACTIVITY_NEW_DOCUMENT is used without
* {@link #FLAG_ACTIVITY_MULTIPLE_TASK} then the activity manager will
@@ -3751,6 +3752,8 @@
* always create a new task. Thus the same document may be made to appear
* more than one time in Recents.
*
+ * <p>This is equivalent to the attribute {@link android.R.attr#documentLaunchMode}.
+ *
* @see #FLAG_ACTIVITY_MULTIPLE_TASK
*/
public static final int FLAG_ACTIVITY_NEW_DOCUMENT =
@@ -3815,6 +3818,15 @@
*/
public static final int FLAG_ACTIVITY_TASK_ON_HOME = 0X00004000;
/**
+ * If set and the new activity is the root of a new task, then the task
+ * will remain in the list of recently launched tasks only until all of
+ * the activities in it are finished.
+ *
+ * <p>This is equivalent to the attribute
+ * {@link android.R.styleable#AndroidManifestActivity_autoRemoveFromRecents}.
+ */
+ public static final int FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS = 0x00002000;
+ /**
* If set, when sending a broadcast only registered receivers will be
* called -- no BroadcastReceiver components will be launched.
*/
@@ -4019,7 +4031,7 @@
/**
* Create an intent for a specific component with a specified action and data.
- * This is equivalent using {@link #Intent(String, android.net.Uri)} to
+ * This is equivalent to using {@link #Intent(String, android.net.Uri)} to
* construct the Intent and then calling {@link #setClass} to set its
* class.
*
diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java
index a9a62a7..9ba45ca 100644
--- a/core/java/android/content/SyncRequest.java
+++ b/core/java/android/content/SyncRequest.java
@@ -473,7 +473,7 @@
* SyncRequest.Builder builder =
* new SyncRequest.Builder()
* .setSyncAdapter(dummyAccount, dummyProvider)
- * .syncOnce(5 * MINUTES_IN_SECS);
+ * .syncOnce();
*
* for (String syncData : syncItems) {
* Bundle extras = new Bundle();
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index c53e545..c2fe3a2 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -67,7 +67,37 @@
* {@link #LAUNCH_SINGLE_INSTANCE}.
*/
public int launchMode;
-
+
+ /**
+ * Constant corresponding to <code>none</code> in
+ * the {@link android.R.attr#documentLaunchMode} attribute.
+ */
+ public static final int DOCUMENT_LAUNCH_NONE = 0;
+ /**
+ * Constant corresponding to <code>intoExisting</code> in
+ * the {@link android.R.attr#documentLaunchMode} attribute.
+ */
+ public static final int DOCUMENT_LAUNCH_INTO_EXISTING = 1;
+ /**
+ * Constant corresponding to <code>always</code> in
+ * the {@link android.R.attr#documentLaunchMode} attribute.
+ */
+ public static final int DOCUMENT_LAUNCH_ALWAYS = 2;
+ /**
+ * The document launch mode style requested by the activity. From the
+ * {@link android.R.attr#documentLaunchMode} attribute, one of
+ * {@link #DOCUMENT_LAUNCH_NONE}, {@link #DOCUMENT_LAUNCH_INTO_EXISTING},
+ * {@link #DOCUMENT_LAUNCH_ALWAYS}.
+ *
+ * <p>Modes DOCUMENT_LAUNCH_ALWAYS
+ * and DOCUMENT_LAUNCH_INTO_EXISTING are equivalent to {@link
+ * android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT
+ * Intent.FLAG_ACTIVITY_NEW_DOCUMENT} with and without {@link
+ * android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
+ * Intent.FLAG_ACTIVITY_MULTIPLE_TASK} respectively.
+ */
+ public int documentLaunchMode;
+
/**
* Optional name of a permission required to be able to access this
* Activity. From the "permission" attribute.
@@ -192,10 +222,15 @@
* Bit in {@link #flags} indicating that this activity is to be persisted across
* reboots for display in the Recents list.
* {@link android.R.attr#persistable}
- * @hide
*/
public static final int FLAG_PERSISTABLE = 0x1000;
/**
+ * Bit in {@link #flags} indicating that tasks started with this activity are to be
+ * removed from the recent list of tasks when the last activity in the task is finished.
+ * {@link android.R.attr#autoRemoveFromRecents}
+ */
+ public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 0x2000;
+ /**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the primary user. Only works with broadcast receivers. Set from the
* android.R.attr#primaryUserOnly attribute.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1a003ff..52a169b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1083,6 +1083,13 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device includes a heart rate monitor.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_SENSOR_HEART_RATE = "android.hardware.sensor.heartrate";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device has a telephony radio with data
* communication support.
*/
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 080b37b..ff96c51 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2462,17 +2462,6 @@
a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
}
- if (sa.getBoolean(
- com.android.internal.R.styleable.AndroidManifestActivity_persistable, false)) {
- a.info.flags |= ActivityInfo.FLAG_PERSISTABLE;
- }
-
- if (sa.getBoolean(
- com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded,
- false)) {
- a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
- }
-
if (!receiver) {
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated,
@@ -2483,6 +2472,9 @@
a.info.launchMode = sa.getInt(
com.android.internal.R.styleable.AndroidManifestActivity_launchMode,
ActivityInfo.LAUNCH_MULTIPLE);
+ a.info.documentLaunchMode = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestActivity_documentLaunchMode,
+ ActivityInfo.DOCUMENT_LAUNCH_NONE);
a.info.screenOrientation = sa.getInt(
com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation,
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
@@ -2492,6 +2484,23 @@
a.info.softInputMode = sa.getInt(
com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode,
0);
+
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestActivity_persistable, false)) {
+ a.info.flags |= ActivityInfo.FLAG_PERSISTABLE;
+ }
+
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded,
+ false)) {
+ a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
+ }
+
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestActivity_autoRemoveFromRecents,
+ false)) {
+ a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
+ }
} else {
a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
a.info.configChanges = 0;
@@ -3591,10 +3600,13 @@
// For use by the package manager to keep track of the path to the
// file an app came from.
public String mScanPath;
-
- // For use by package manager to keep track of where it has done dexopt.
- public boolean mDidDexOpt;
-
+
+ // For use by package manager to keep track of where it needs to do dexopt.
+ public boolean mDexOptNeeded = true;
+
+ // For use by package manager to keep track of when a package was last used.
+ public long mLastPackageUsageTimeInMills;
+
// // User set enabled state.
// public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
//
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 28309d7..5f2af8cf 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1277,20 +1277,6 @@
new Key<Integer>("android.sensor.orientation", int.class);
/**
- * <p>The number of input samples for each dimension of
- * {@link CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP android.sensor.profileHueSatMap}.</p>
- * <p>The number of input samples for the hue, saturation, and value
- * dimension of {@link CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP android.sensor.profileHueSatMap}. The order of the
- * dimensions given is hue, saturation, value; where hue is the 0th
- * element.</p>
- * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
- *
- * @see CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP
- */
- public static final Key<int[]> SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS =
- new Key<int[]>("android.sensor.profileHueSatMapDimensions", int[].class);
-
- /**
* <p>Optional. Defaults to [OFF]. Lists the supported test
* pattern modes for {@link CaptureRequest#SENSOR_TEST_PATTERN_MODE android.sensor.testPatternMode}.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 1d2d0e9..51ea447 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -1906,36 +1906,6 @@
new Key<Rational[]>("android.sensor.neutralColorPoint", Rational[].class);
/**
- * <p>A mapping containing a hue shift, saturation scale, and value scale
- * for each pixel.</p>
- * <p>hue_samples, saturation_samples, and value_samples are given in
- * {@link CameraCharacteristics#SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS android.sensor.profileHueSatMapDimensions}.</p>
- * <p>Each entry of this map contains three floats corresponding to the
- * hue shift, saturation scale, and value scale, respectively; where the
- * hue shift has the lowest index. The map entries are stored in the tag
- * in nested loop order, with the value divisions in the outer loop, the
- * hue divisions in the middle loop, and the saturation divisions in the
- * inner loop. All zero input saturation entries are required to have a
- * value scale factor of 1.0.</p>
- * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
- *
- * @see CameraCharacteristics#SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS
- */
- public static final Key<float[]> SENSOR_PROFILE_HUE_SAT_MAP =
- new Key<float[]>("android.sensor.profileHueSatMap", float[].class);
-
- /**
- * <p>A list of x,y samples defining a tone-mapping curve for gamma adjustment.</p>
- * <p>This tag contains a default tone curve that can be applied while
- * processing the image as a starting point for user adjustments.
- * The curve is specified as a list of value pairs in linear gamma.
- * The curve is interpolated using a cubic spline.</p>
- * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
- */
- public static final Key<float[]> SENSOR_PROFILE_TONE_CURVE =
- new Key<float[]>("android.sensor.profileToneCurve", float[].class);
-
- /**
* <p>The worst-case divergence between Bayer green channels.</p>
* <p>This value is an estimate of the worst case split between the
* Bayer green channels in the red and blue rows in the sensor color
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 3da00b1..30d7043 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1307,14 +1307,13 @@
* doing something unusual like general internal filtering this may be useful. On
* a private network where the proxy is not accessible, you may break HTTP using this.
*
- * @param p The a {@link ProxyProperties} object defining the new global
+ * @param p The a {@link ProxyInfo} object defining the new global
* HTTP proxy. A {@code null} value will clear the global HTTP proxy.
*
* <p>This method requires the call to hold the permission
- * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
- * {@hide}
+ * android.Manifest.permission#CONNECTIVITY_INTERNAL.
*/
- public void setGlobalProxy(ProxyProperties p) {
+ public void setGlobalProxy(ProxyInfo p) {
try {
mService.setGlobalProxy(p);
} catch (RemoteException e) {
@@ -1324,14 +1323,13 @@
/**
* Retrieve any network-independent global HTTP proxy.
*
- * @return {@link ProxyProperties} for the current global HTTP proxy or {@code null}
+ * @return {@link ProxyInfo} for the current global HTTP proxy or {@code null}
* if no global HTTP proxy is set.
*
* <p>This method requires the call to hold the permission
* {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
- * {@hide}
*/
- public ProxyProperties getGlobalProxy() {
+ public ProxyInfo getGlobalProxy() {
try {
return mService.getGlobalProxy();
} catch (RemoteException e) {
@@ -1343,14 +1341,14 @@
* Get the HTTP proxy settings for the current default network. Note that
* if a global proxy is set, it will override any per-network setting.
*
- * @return the {@link ProxyProperties} for the current HTTP proxy, or {@code null} if no
+ * @return the {@link ProxyInfo} for the current HTTP proxy, or {@code null} if no
* HTTP proxy is active.
*
* <p>This method requires the call to hold the permission
* {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
* {@hide}
*/
- public ProxyProperties getProxy() {
+ public ProxyInfo getProxy() {
try {
return mService.getProxy();
} catch (RemoteException e) {
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 381a817..d53a856 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -21,7 +21,7 @@
import android.net.NetworkInfo;
import android.net.NetworkQuotaInfo;
import android.net.NetworkState;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
import android.os.IBinder;
import android.os.Messenger;
import android.os.ParcelFileDescriptor;
@@ -107,11 +107,11 @@
void reportInetCondition(int networkType, int percentage);
- ProxyProperties getGlobalProxy();
+ ProxyInfo getGlobalProxy();
- void setGlobalProxy(in ProxyProperties p);
+ void setGlobalProxy(in ProxyInfo p);
- ProxyProperties getProxy();
+ ProxyInfo getProxy();
void setDataDependency(int networkType, boolean met);
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 4dfd3d9..2dcc544 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -16,7 +16,7 @@
package android.net;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
import android.os.Parcelable;
import android.os.Parcel;
import android.text.TextUtils;
@@ -65,7 +65,7 @@
private ArrayList<InetAddress> mDnses = new ArrayList<InetAddress>();
private String mDomains;
private ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
- private ProxyProperties mHttpProxy;
+ private ProxyInfo mHttpProxy;
private int mMtu;
// Stores the properties of links that are "stacked" above this link.
@@ -101,7 +101,7 @@
mDomains = source.getDomains();
for (RouteInfo r : source.getRoutes()) mRoutes.add(r);
mHttpProxy = (source.getHttpProxy() == null) ?
- null : new ProxyProperties(source.getHttpProxy());
+ null : new ProxyInfo(source.getHttpProxy());
for (LinkProperties l: source.mStackedLinks.values()) {
addStackedLink(l);
}
@@ -295,10 +295,10 @@
return routes;
}
- public void setHttpProxy(ProxyProperties proxy) {
+ public void setHttpProxy(ProxyInfo proxy) {
mHttpProxy = proxy;
}
- public ProxyProperties getHttpProxy() {
+ public ProxyInfo getHttpProxy() {
return mHttpProxy;
}
@@ -720,7 +720,7 @@
netProp.addRoute((RouteInfo)in.readParcelable(null));
}
if (in.readByte() == 1) {
- netProp.setHttpProxy((ProxyProperties)in.readParcelable(null));
+ netProp.setHttpProxy((ProxyInfo)in.readParcelable(null));
}
ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
in.readList(stackedLinks, LinkProperties.class.getClassLoader());
diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java
index bea8d1c..8f41e85 100644
--- a/core/java/android/net/Proxy.java
+++ b/core/java/android/net/Proxy.java
@@ -19,6 +19,7 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
+import android.net.ProxyInfo;
import android.text.TextUtils;
import android.util.Log;
@@ -63,8 +64,11 @@
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
- /** {@hide} **/
- public static final String EXTRA_PROXY_INFO = "proxy";
+ /**
+ * Intent extra included with {@link #PROXY_CHANGE_ACTION} intents.
+ * It describes the new proxy being used (as a {@link ProxyInfo} object).
+ */
+ public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
/** @hide */
public static final int PROXY_VALID = 0;
@@ -114,24 +118,14 @@
*/
public static final java.net.Proxy getProxy(Context ctx, String url) {
String host = "";
- if (url != null) {
+ if ((url != null) && !isLocalHost(host)) {
URI uri = URI.create(url);
- host = uri.getHost();
- }
+ ProxySelector proxySelector = ProxySelector.getDefault();
- if (!isLocalHost(host)) {
- if (sConnectivityManager == null) {
- sConnectivityManager = (ConnectivityManager)ctx.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- }
- if (sConnectivityManager == null) return java.net.Proxy.NO_PROXY;
+ List<java.net.Proxy> proxyList = proxySelector.select(uri);
- ProxyProperties proxyProperties = sConnectivityManager.getProxy();
-
- if (proxyProperties != null) {
- if (!proxyProperties.isExcluded(host)) {
- return proxyProperties.makeProxy();
- }
+ if (proxyList.size() > 0) {
+ return proxyList.get(0);
}
}
return java.net.Proxy.NO_PROXY;
@@ -275,7 +269,7 @@
}
/** @hide */
- public static final void setHttpProxySystemProperty(ProxyProperties p) {
+ public static final void setHttpProxySystemProperty(ProxyInfo p) {
String host = null;
String port = null;
String exclList = null;
@@ -283,8 +277,8 @@
if (p != null) {
host = p.getHost();
port = Integer.toString(p.getPort());
- exclList = p.getExclusionList();
- pacFileUrl = p.getPacFileUrl();
+ exclList = p.getExclusionListAsString();
+ pacFileUrl = p.getPacFileUrl().toString();
}
setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
}
diff --git a/core/java/android/net/ProxyProperties.aidl b/core/java/android/net/ProxyInfo.aidl
similarity index 95%
rename from core/java/android/net/ProxyProperties.aidl
rename to core/java/android/net/ProxyInfo.aidl
index 02ea15d..2c91960 100644
--- a/core/java/android/net/ProxyProperties.aidl
+++ b/core/java/android/net/ProxyInfo.aidl
@@ -17,5 +17,5 @@
package android.net;
-parcelable ProxyProperties;
+parcelable ProxyInfo;
diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyInfo.java
similarity index 61%
rename from core/java/android/net/ProxyProperties.java
rename to core/java/android/net/ProxyInfo.java
index 50f45e8..b40941f 100644
--- a/core/java/android/net/ProxyProperties.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -21,14 +21,23 @@
import android.os.Parcelable;
import android.text.TextUtils;
+import org.apache.http.client.HttpClient;
+
import java.net.InetSocketAddress;
+import java.net.URLConnection;
+import java.util.List;
import java.util.Locale;
/**
- * A container class for the http proxy info
- * @hide
+ * Describes a proxy configuration.
+ *
+ * Proxy configurations are already integrated within the Apache HTTP stack.
+ * So {@link URLConnection} and {@link HttpClient} will use them automatically.
+ *
+ * Other HTTP stacks will need to obtain the proxy info from
+ * {@link Proxy#PROXY_CHANGE_ACTION} broadcast as the extra {@link Proxy#EXTRA_PROXY_INFO}.
*/
-public class ProxyProperties implements Parcelable {
+public class ProxyInfo implements Parcelable {
private String mHost;
private int mPort;
@@ -36,32 +45,82 @@
private String[] mParsedExclusionList;
private String mPacFileUrl;
+ /**
+ *@hide
+ */
public static final String LOCAL_EXCL_LIST = "";
+ /**
+ *@hide
+ */
public static final int LOCAL_PORT = -1;
+ /**
+ *@hide
+ */
public static final String LOCAL_HOST = "localhost";
- public ProxyProperties(String host, int port, String exclList) {
+ /**
+ * Constructs a {@link ProxyInfo} object that points at a Direct proxy
+ * on the specified host and port.
+ */
+ public static ProxyInfo buildDirectProxy(String host, int port) {
+ return new ProxyInfo(host, port, null);
+ }
+
+ /**
+ * Constructs a {@link ProxyInfo} object that points at a Direct proxy
+ * on the specified host and port.
+ *
+ * The proxy will not be used to access any host in exclusion list, exclList.
+ *
+ * @param exclList Hosts to exclude using the proxy on connections for. These
+ * hosts can use wildcards such as *.example.com.
+ */
+ public static ProxyInfo buildDirectProxy(String host, int port, List<String> exclList) {
+ String[] array = exclList.toArray(new String[exclList.size()]);
+ return new ProxyInfo(host, port, TextUtils.join(",", array), array);
+ }
+
+ /**
+ * Construct a {@link ProxyInfo} that will download and run the PAC script
+ * at the specified URL.
+ */
+ public static ProxyInfo buildPacProxy(Uri pacUri) {
+ return new ProxyInfo(pacUri.toString());
+ }
+
+ /**
+ * Create a ProxyProperties that points at a HTTP Proxy.
+ * @hide
+ */
+ public ProxyInfo(String host, int port, String exclList) {
mHost = host;
mPort = port;
setExclusionList(exclList);
}
- public ProxyProperties(String pacFileUrl) {
+ /**
+ * Create a ProxyProperties that points at a PAC URL.
+ * @hide
+ */
+ public ProxyInfo(String pacFileUrl) {
mHost = LOCAL_HOST;
mPort = LOCAL_PORT;
setExclusionList(LOCAL_EXCL_LIST);
mPacFileUrl = pacFileUrl;
}
- // Only used in PacManager after Local Proxy is bound.
- public ProxyProperties(String pacFileUrl, int localProxyPort) {
+ /**
+ * Only used in PacManager after Local Proxy is bound.
+ * @hide
+ */
+ public ProxyInfo(String pacFileUrl, int localProxyPort) {
mHost = LOCAL_HOST;
mPort = localProxyPort;
setExclusionList(LOCAL_EXCL_LIST);
mPacFileUrl = pacFileUrl;
}
- private ProxyProperties(String host, int port, String exclList, String[] parsedExclList) {
+ private ProxyInfo(String host, int port, String exclList, String[] parsedExclList) {
mHost = host;
mPort = port;
mExclusionList = exclList;
@@ -70,16 +129,22 @@
}
// copy constructor instead of clone
- public ProxyProperties(ProxyProperties source) {
+ /**
+ * @hide
+ */
+ public ProxyInfo(ProxyInfo source) {
if (source != null) {
mHost = source.getHost();
mPort = source.getPort();
- mPacFileUrl = source.getPacFileUrl();
- mExclusionList = source.getExclusionList();
+ mPacFileUrl = source.mPacFileUrl;
+ mExclusionList = source.getExclusionListAsString();
mParsedExclusionList = source.mParsedExclusionList;
}
}
+ /**
+ * @hide
+ */
public InetSocketAddress getSocketAddress() {
InetSocketAddress inetSocketAddress = null;
try {
@@ -88,20 +153,46 @@
return inetSocketAddress;
}
- public String getPacFileUrl() {
- return mPacFileUrl;
+ /**
+ * Returns the URL of the current PAC script or null if there is
+ * no PAC script.
+ */
+ public Uri getPacFileUrl() {
+ if (TextUtils.isEmpty(mPacFileUrl)) {
+ return null;
+ }
+ return Uri.parse(mPacFileUrl);
}
+ /**
+ * When configured to use a Direct Proxy this returns the host
+ * of the proxy.
+ */
public String getHost() {
return mHost;
}
+ /**
+ * When configured to use a Direct Proxy this returns the port
+ * of the proxy
+ */
public int getPort() {
return mPort;
}
- // comma separated
- public String getExclusionList() {
+ /**
+ * When configured to use a Direct Proxy this returns the list
+ * of hosts for which the proxy is ignored.
+ */
+ public String[] getExclusionList() {
+ return mParsedExclusionList;
+ }
+
+ /**
+ * comma separated
+ * @hide
+ */
+ public String getExclusionListAsString() {
return mExclusionList;
}
@@ -111,33 +202,13 @@
if (mExclusionList == null) {
mParsedExclusionList = new String[0];
} else {
- String splitExclusionList[] = exclusionList.toLowerCase(Locale.ROOT).split(",");
- mParsedExclusionList = new String[splitExclusionList.length * 2];
- for (int i = 0; i < splitExclusionList.length; i++) {
- String s = splitExclusionList[i].trim();
- if (s.startsWith(".")) s = s.substring(1);
- mParsedExclusionList[i*2] = s;
- mParsedExclusionList[(i*2)+1] = "." + s;
- }
+ mParsedExclusionList = exclusionList.toLowerCase(Locale.ROOT).split(",");
}
}
- public boolean isExcluded(String url) {
- if (TextUtils.isEmpty(url) || mParsedExclusionList == null ||
- mParsedExclusionList.length == 0) return false;
-
- Uri u = Uri.parse(url);
- String urlDomain = u.getHost();
- if (urlDomain == null) return false;
- for (int i = 0; i< mParsedExclusionList.length; i+=2) {
- if (urlDomain.equals(mParsedExclusionList[i]) ||
- urlDomain.endsWith(mParsedExclusionList[i+1])) {
- return true;
- }
- }
- return false;
- }
-
+ /**
+ * @hide
+ */
public boolean isValid() {
if (!TextUtils.isEmpty(mPacFileUrl)) return true;
return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost,
@@ -145,6 +216,9 @@
mExclusionList == null ? "" : mExclusionList);
}
+ /**
+ * @hide
+ */
public java.net.Proxy makeProxy() {
java.net.Proxy proxy = java.net.Proxy.NO_PROXY;
if (mHost != null) {
@@ -179,17 +253,17 @@
@Override
public boolean equals(Object o) {
- if (!(o instanceof ProxyProperties)) return false;
- ProxyProperties p = (ProxyProperties)o;
+ if (!(o instanceof ProxyInfo)) return false;
+ ProxyInfo p = (ProxyInfo)o;
// If PAC URL is present in either then they must be equal.
// Other parameters will only be for fall back.
if (!TextUtils.isEmpty(mPacFileUrl)) {
return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort;
}
- if (!TextUtils.isEmpty(p.getPacFileUrl())) {
+ if (!TextUtils.isEmpty(p.mPacFileUrl)) {
return false;
}
- if (mExclusionList != null && !mExclusionList.equals(p.getExclusionList())) return false;
+ if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) return false;
if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) {
return false;
}
@@ -245,15 +319,15 @@
* Implement the Parcelable interface.
* @hide
*/
- public static final Creator<ProxyProperties> CREATOR =
- new Creator<ProxyProperties>() {
- public ProxyProperties createFromParcel(Parcel in) {
+ public static final Creator<ProxyInfo> CREATOR =
+ new Creator<ProxyInfo>() {
+ public ProxyInfo createFromParcel(Parcel in) {
String host = null;
int port = 0;
if (in.readByte() != 0) {
String url = in.readString();
int localPort = in.readInt();
- return new ProxyProperties(url, localPort);
+ return new ProxyInfo(url, localPort);
}
if (in.readByte() != 0) {
host = in.readString();
@@ -261,13 +335,13 @@
}
String exclList = in.readString();
String[] parsedExclList = in.readStringArray();
- ProxyProperties proxyProperties =
- new ProxyProperties(host, port, exclList, parsedExclList);
+ ProxyInfo proxyProperties =
+ new ProxyInfo(host, port, exclList, parsedExclList);
return proxyProperties;
}
- public ProxyProperties[] newArray(int size) {
- return new ProxyProperties[size];
+ public ProxyInfo[] newArray(int size) {
+ return new ProxyInfo[size];
}
};
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1b2b798..e379621 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -91,7 +91,6 @@
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
-
public static final String DISALLOW_SHARE_LOCATION = "no_share_location";
/**
@@ -145,6 +144,128 @@
*/
public static final String DISALLOW_REMOVE_USER = "no_remove_user";
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from enabling or
+ * accessing debugging features. The default value is <code>false</code>.
+ * <p/>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from configuring VPN.
+ * The default value is <code>false</code>.
+ * <p/>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONFIG_VPN = "no_config_vpn";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from configuring Tethering
+ * & portable hotspots. The default value is <code>false</code>.
+ * <p/>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from factory resetting
+ * from Settings.
+ * The default value is <code>false</code>.
+ * <p>
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_FACTORY_RESET = "no_factory_reset";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from adding new users and
+ * profiles. The default value is <code>false</code>.
+ * <p>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_ADD_USER = "no_add_user";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from disabling application
+ * verification. The default value is <code>false</code>.
+ * <p>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String ENSURE_VERIFY_APPS = "ensure_verify_apps";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from configuring cell
+ * broadcasts. The default value is <code>false</code>.
+ * <p>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from configuring mobile
+ * networks. The default value is <code>false</code>.
+ * <p>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from configuring
+ * applications in Settings. The default value is <code>false</code>.
+ * <p>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONFIG_APPS = "no_config_apps";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from mounting
+ * physical external media. The default value is <code>false</code>.
+ * <p/>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from adjusting microphone
+ * volume.
+ * The default value is <code>false</code>.
+ * <p/>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from adjusting the master
+ * volume.
+ * The default value is <code>false</code>.
+ * <p/>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
+
/** @hide */
public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3;
/** @hide */
@@ -572,7 +693,7 @@
/**
* Returns information for all users on this device. Requires
* {@link android.Manifest.permission#MANAGE_USERS} permission.
- *
+ *
* @param excludeDying specify if the list should exclude users being
* removed.
* @return the list of users that were created.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0eb994d..dc618c8 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2823,7 +2823,6 @@
MOVED_TO_GLOBAL.add(Settings.Global.TETHER_SUPPORTED);
MOVED_TO_GLOBAL.add(Settings.Global.USB_MASS_STORAGE_ENABLED);
MOVED_TO_GLOBAL.add(Settings.Global.USE_GOOGLE_MAIL);
- MOVED_TO_GLOBAL.add(Settings.Global.WEB_AUTOFILL_QUERY_URL);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_COUNTRY_CODE);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_FREQUENCY_BAND);
@@ -2838,6 +2837,8 @@
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SAVED_STATE);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED);
+ MOVED_TO_GLOBAL.add(Settings.Global.WIFI_ENHANCED_AUTO_JOIN);
+ MOVED_TO_GLOBAL.add(Settings.Global.WIFI_NETWORK_SHOW_RSSI);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_ON);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED);
MOVED_TO_GLOBAL.add(Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON);
@@ -3480,6 +3481,12 @@
"lock_screen_appwidget_ids";
/**
+ * List of enrolled fingerprint identifiers (comma-delimited).
+ * @hide
+ */
+ public static final String USER_FINGERPRINT_IDS = "user_fingerprint_ids";
+
+ /**
* Id of the appwidget shown on the lock screen when appwidgets are disabled.
* @hide
*/
@@ -5347,11 +5354,6 @@
*/
public static final String USE_GOOGLE_MAIL = "use_google_mail";
- /** Autofill server address (Used in WebView/browser).
- * {@hide} */
- public static final String WEB_AUTOFILL_QUERY_URL =
- "web_autofill_query_url";
-
/**
* Whether Wifi display is enabled/disabled
* 0=disabled. 1=enabled.
@@ -5463,7 +5465,21 @@
public static final String WIFI_SUPPLICANT_SCAN_INTERVAL_MS =
"wifi_supplicant_scan_interval_ms";
- /**
+ /**
+ * whether frameworks handles wifi auto-join
+ * @hide
+ */
+ public static final String WIFI_ENHANCED_AUTO_JOIN =
+ "wifi_enhanced_auto_join";
+
+ /**
+ * whether settings show RSSI
+ * @hide
+ */
+ public static final String WIFI_NETWORK_SHOW_RSSI =
+ "wifi_network_show_rssi";
+
+ /**
* The interval in milliseconds to scan at supplicant when p2p is connected
* @hide
*/
diff --git a/core/java/android/service/fingerprint/FingerprintManager.java b/core/java/android/service/fingerprint/FingerprintManager.java
new file mode 100644
index 0000000..0d14c59
--- /dev/null
+++ b/core/java/android/service/fingerprint/FingerprintManager.java
@@ -0,0 +1,200 @@
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.fingerprint;
+
+import android.app.ActivityManagerNative;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+/**
+ * A class that coordinates access to the fingerprint hardware.
+ */
+
+public class FingerprintManager {
+ private static final String TAG = "FingerprintManager";
+ protected static final boolean DEBUG = true;
+ private static final String FINGERPRINT_SERVICE_PACKAGE = "com.android.service.fingerprint";
+ private static final String FINGERPRINT_SERVICE_CLASS =
+ "com.android.service.fingerprint.FingerprintService";
+ private static final int MSG_ENROLL_RESULT = 100;
+ private static final int MSG_SCANNED = 101;
+ private static final int MSG_ERROR = 102;
+ private static final int MSG_REMOVED = 103;
+
+ public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10;
+ public static final int FINGERPRINT_ERROR = -1; // One of the error messages below.
+
+ // Progress messages.
+ public static final int FINGERPRINT_SCANNED = 1;
+ public static final int FINGERPRINT_TEMPLATE_ENROLLING = 2;
+ public static final int FINGERPRINT_TEMPLATE_REMOVED = 4;
+
+ // Error messages. Must agree with fingerprint HAL definitions.
+ public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1;
+ public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2;
+ public static final int FINGERPRINT_ERROR_TIMEOUT = 3;
+ public static final int FINGERPRINT_ERROR_NO_SPACE = 4;
+
+ private IFingerprintService mService;
+ private FingerprintManagerReceiver mClientReceiver;
+
+ private Handler mHandler = new Handler() {
+ public void handleMessage(android.os.Message msg) {
+ if (mClientReceiver != null) {
+ switch(msg.what) {
+ case MSG_ENROLL_RESULT:
+ mClientReceiver.onEnrollResult(msg.arg1, msg.arg2);
+ break;
+ case MSG_SCANNED:
+ mClientReceiver.onScanned(msg.arg1, msg.arg2);
+ break;
+ case MSG_ERROR:
+ mClientReceiver.onError(msg.arg1);
+ break;
+ case MSG_REMOVED:
+ mClientReceiver.onRemoved(msg.arg1);
+ }
+ }
+ }
+ };
+
+ public FingerprintManager(Context context) {
+ // Connect to service...
+ Intent intent = new Intent();
+ intent.setClassName(FINGERPRINT_SERVICE_PACKAGE, FINGERPRINT_SERVICE_CLASS);
+ if (!context.bindServiceAsUser(intent, mFingerprintConnection,
+ Context.BIND_AUTO_CREATE, UserHandle.CURRENT_OR_SELF)) {
+ if (DEBUG) Log.v(TAG, "Can't bind to " + FINGERPRINT_SERVICE_CLASS);
+ }
+ }
+
+ private final ServiceConnection mFingerprintConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (DEBUG) Log.v(TAG, "Connected to FingerprintService");
+ mService = IFingerprintService.Stub.asInterface(service);
+ try {
+ mService.startListening(mServiceReceiver, getCurrentUserId());
+ } catch (RemoteException e) {
+ if (DEBUG) Log.v(TAG, "Failed to set callback", e);
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG) Log.v(TAG, "Disconnected from FingerprintService");
+ mService = null;
+ }
+ };
+
+ private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
+
+ public void onEnrollResult(int fingerprintId, int remaining) {
+ mHandler.obtainMessage(MSG_ENROLL_RESULT, fingerprintId, remaining).sendToTarget();
+ }
+
+ public void onScanned(int fingerprintId, int confidence) {
+ mHandler.obtainMessage(MSG_SCANNED, fingerprintId, confidence)
+ .sendToTarget();;
+ }
+
+ public void onError(int error) {
+ mHandler.obtainMessage(MSG_ERROR, error, 0).sendToTarget();
+ }
+
+ public void onRemoved(int fingerprintId) {
+ mHandler.obtainMessage(MSG_REMOVED, fingerprintId, 0).sendToTarget();
+ }
+ };
+
+ /**
+ * Start the enrollment process. Timeout dictates how long to wait for the user to
+ * enroll a fingerprint.
+ *
+ * @param timeout
+ */
+ public void enroll(long timeout) {
+ if (mServiceReceiver == null) {
+ throw new IllegalStateException("enroll: Call registerCallback() first");
+ }
+ if (mService != null) try {
+ mService.enroll(timeout, getCurrentUserId());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception while enrolling: ", e);
+ }
+ }
+
+ /**
+ * Remove the given fingerprintId from the system. FingerprintId of 0 has special meaning
+ * which is to delete all fingerprint data for the current user. Use with caution.
+ * @param fingerprintId
+ */
+ public void remove(int fingerprintId) {
+ if (mService != null) try {
+ mService.remove(fingerprintId, getCurrentUserId());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception during remove of fingerprintId: " + fingerprintId, e);
+ }
+ }
+
+ /**
+ * Starts listening for fingerprint events. When a finger is scanned or recognized, the
+ * client will be notified via the callback.
+ */
+ public void startListening(FingerprintManagerReceiver receiver) {
+ mClientReceiver = receiver;
+ if (mService != null) {
+ try {
+ mService.startListening(mServiceReceiver, getCurrentUserId());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception in startListening(): ", e);
+ }
+ }
+ }
+
+ private int getCurrentUserId() {
+ try {
+ return ActivityManagerNative.getDefault().getCurrentUser().id;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get current user id\n");
+ return UserHandle.USER_NULL;
+ }
+ }
+
+ /**
+ * Stops the client from listening to fingerprint events.
+ */
+ public void stopListening() {
+ mClientReceiver = null;
+ if (mService != null) {
+ try {
+ mService.stopListening(getCurrentUserId());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception in stopListening(): ", e);
+ }
+ } else {
+ Log.w(TAG, "stopListening(): Service not connected!");
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
new file mode 100644
index 0000000..34f1655
--- /dev/null
+++ b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
@@ -0,0 +1,59 @@
+package android.service.fingerprint;
+/**
+ * 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.
+ */
+
+public class FingerprintManagerReceiver {
+ /**
+ * Fingerprint enrollment progress update. Enrollment is considered complete if
+ * remaining hits 0 without {@link #onError(int)} being called.
+ *
+ * @param fingerprintId the fingerprint we're currently enrolling
+ * @param remaining the number of samples required to complete enrollment. It's up to
+ * the hardware to define what each step in enrollment means. Some hardware
+ * requires multiple samples of the same part of the finger. Others require sampling of
+ * different parts of the finger. The enrollment flow can use remaining to
+ * mean "step x" of the process or "just need another sample."
+ */
+ public void onEnrollResult(int fingerprintId, int remaining) { }
+
+ /**
+ * Fingerprint scan detected. Most clients will use this function to detect a fingerprint
+ *
+ * @param fingerprintId is the finger the hardware has detected.
+ * @param confidence from 0 (no confidence) to 65535 (high confidence). Fingerprint 0 has
+ * special meaning - the finger wasn't recognized.
+ */
+ public void onScanned(int fingerprintId, int confidence) { }
+
+ /**
+ * An error was detected during scan or enrollment. One of
+ * {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE},
+ * {@link FingerprintManager#FINGERPRINT_ERROR_BAD_CAPTURE} or
+ * {@link FingerprintManager#FINGERPRINT_ERROR_TIMEOUT}
+ * {@link FingerprintManager#FINGERPRINT_ERROR_NO_SPACE}
+ *
+ * @param error one of the above error codes
+ */
+ public void onError(int error) { }
+
+ /**
+ * The given fingerprint template was successfully removed by the driver.
+ * See {@link FingerprintManager#remove(int)}
+ *
+ * @param fingerprintId id of template to remove.
+ */
+ public void onRemoved(int fingerprintId) { }
+}
\ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintService.java b/core/java/android/service/fingerprint/FingerprintService.java
new file mode 100644
index 0000000..c7fa7cd
--- /dev/null
+++ b/core/java/android/service/fingerprint/FingerprintService.java
@@ -0,0 +1,219 @@
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.fingerprint;
+
+import android.app.Service;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.util.HashMap;
+
+/**
+ * A service to manage multiple clients that want to access the fingerprint HAL API.
+ * The service is responsible for maintaining a list of clients and dispatching all
+ * fingerprint -related events.
+ *
+ * @hide
+ */
+public class FingerprintService extends Service {
+ private final String TAG = FingerprintService.class.getSimpleName() +
+ "[" + getClass().getSimpleName() + "]";
+ private static final boolean DEBUG = true;
+ HashMap<IFingerprintServiceReceiver, ClientData> mClients =
+ new HashMap<IFingerprintServiceReceiver, ClientData>();
+
+ private static final int MSG_NOTIFY = 10;
+
+ Handler mHandler = new Handler() {
+ public void handleMessage(android.os.Message msg) {
+ switch (msg.what) {
+ case MSG_NOTIFY:
+ handleNotify(msg.arg1, msg.arg2, (Integer) msg.obj);
+ break;
+
+ default:
+ Slog.w(TAG, "Unknown message:" + msg.what);
+ }
+ }
+ };
+
+ private static final int STATE_IDLE = 0;
+ private static final int STATE_LISTENING = 1;
+ private static final int STATE_ENROLLING = 2;
+ private static final int STATE_DELETING = 3;
+ private static final long MS_PER_SEC = 1000;
+
+ private static final class ClientData {
+ public IFingerprintServiceReceiver receiver;
+ int state;
+ int userId;
+ }
+
+ @Override
+ public final IBinder onBind(Intent intent) {
+ if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
+ return new FingerprintServiceWrapper();
+ }
+
+ // JNI methods to communicate from FingerprintManagerService to HAL
+ native int nativeEnroll(int timeout);
+ native int nativeRemove(int fingerprintId);
+
+ // JNI methods for communicating from HAL to clients
+ void notify(int msg, int arg1, int arg2) {
+ mHandler.obtainMessage(MSG_NOTIFY, msg, arg1, arg2).sendToTarget();
+ }
+
+ void handleNotify(int msg, int arg1, int arg2) {
+ for (int i = 0; i < mClients.size(); i++) {
+ ClientData clientData = mClients.get(i);
+ switch (msg) {
+ case FingerprintManager.FINGERPRINT_ERROR: {
+ if (clientData.state != STATE_IDLE) {
+ // FINGERPRINT_ERROR_HW_UNAVAILABLE
+ // FINGERPRINT_ERROR_BAD_CAPTURE
+ // FINGERPRINT_ERROR_TIMEOUT
+ // FINGERPRINT_ERROR_NO_SPACE
+ final int error = arg1;
+ clientData.state = STATE_IDLE;
+ if (clientData.receiver != null) {
+ try {
+ clientData.receiver.onError(error);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ }
+ }
+ }
+ }
+ break;
+ case FingerprintManager.FINGERPRINT_SCANNED: {
+ final int fingerId = arg1;
+ final int confidence = arg2;
+ if (clientData.state == STATE_LISTENING && clientData.receiver != null) {
+ try {
+ clientData.receiver.onScanned(fingerId, confidence);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ }
+ }
+ break;
+ }
+ case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
+ if (clientData.state == STATE_ENROLLING) {
+ final int fingerId = arg1;
+ final int remaining = arg2;
+ if (remaining == 0) {
+ FingerprintUtils.addFingerprintIdForUser(fingerId,
+ getContentResolver(), clientData.userId);
+ clientData.state = STATE_IDLE; // Nothing left to do
+ }
+ if (clientData.receiver != null) {
+ try {
+ clientData.receiver.onEnrollResult(fingerId, remaining);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ }
+ }
+ }
+ break;
+ }
+ case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: {
+ int fingerId = arg1;
+ if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL");
+ if (clientData.state == STATE_DELETING) {
+ FingerprintUtils.removeFingerprintIdForUser(fingerId, getContentResolver(),
+ clientData.userId);
+ if (clientData.receiver != null) {
+ try {
+ clientData.receiver.onRemoved(fingerId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ int enroll(IFingerprintServiceReceiver receiver, long timeout, int userId) {
+ ClientData clientData = mClients.get(receiver);
+ if (clientData != null) {
+ if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+ clientData.state = STATE_ENROLLING;
+ return nativeEnroll((int) (timeout / MS_PER_SEC));
+ }
+ return -1;
+ }
+
+ int remove(IFingerprintServiceReceiver receiver, int fingerId, int userId) {
+ ClientData clientData = mClients.get(receiver);
+ if (clientData != null) {
+ if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+ clientData.state = STATE_DELETING;
+ // The fingerprint id will be removed when we get confirmation from the HAL
+ return nativeRemove(fingerId);
+ }
+ return -1;
+ }
+
+ void startListening(IFingerprintServiceReceiver receiver, int userId) {
+ ClientData clientData = new ClientData();
+ clientData.state = STATE_LISTENING;
+ clientData.receiver = receiver;
+ clientData.userId = userId;
+ mClients.put(receiver, clientData);
+ }
+
+ void stopListening(IFingerprintServiceReceiver receiver, int userId) {
+ ClientData clientData = mClients.get(receiver);
+ if (clientData != null) {
+ clientData.state = STATE_IDLE;
+ clientData.userId = -1;
+ clientData.receiver = null;
+ }
+ mClients.remove(receiver);
+ }
+
+ private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
+ IFingerprintServiceReceiver mReceiver;
+ public int enroll(long timeout, int userId) {
+ return mReceiver != null ? FingerprintService.this.enroll(mReceiver, timeout, userId)
+ : FingerprintManager.FINGERPRINT_ERROR_NO_RECEIVER;
+ }
+
+ public int remove(int fingerprintId, int userId) {
+ return FingerprintService.this.remove(mReceiver, fingerprintId, userId);
+ }
+
+ public void startListening(IFingerprintServiceReceiver receiver, int userId) {
+ mReceiver = receiver;
+ FingerprintService.this.startListening(receiver, userId);
+ }
+
+ public void stopListening(int userId) {
+ FingerprintService.this.stopListening(mReceiver, userId);
+ }
+ }
+}
diff --git a/core/java/android/service/fingerprint/FingerprintUtils.java b/core/java/android/service/fingerprint/FingerprintUtils.java
new file mode 100644
index 0000000..81a2aac
--- /dev/null
+++ b/core/java/android/service/fingerprint/FingerprintUtils.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.fingerprint;
+
+import android.content.ContentResolver;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.Arrays;
+
+class FingerprintUtils {
+ private static final boolean DEBUG = true;
+ private static final String TAG = "FingerprintUtils";
+
+ public static int[] getFingerprintIdsForUser(ContentResolver res, int userId) {
+ String fingerIdsRaw = Settings.Secure.getStringForUser(res,
+ Settings.Secure.USER_FINGERPRINT_IDS, userId);
+
+ String[] fingerStringIds = fingerIdsRaw.replace("[","").replace("]","").split(", ");
+ int result[] = new int[fingerStringIds.length];
+ for (int i = 0; i < result.length; i++) {
+ try {
+ result[i] = Integer.decode(fingerStringIds[i]);
+ } catch (NumberFormatException e) {
+ if (DEBUG) Log.d(TAG, "Error when parsing finger id " + fingerStringIds[i]);
+ }
+ }
+ return result;
+ }
+
+ public static void addFingerprintIdForUser(int fingerId, ContentResolver res, int userId) {
+ int[] fingerIds = getFingerprintIdsForUser(res, userId);
+
+ // FingerId 0 has special meaning.
+ if (fingerId == 0) return;
+
+ // Don't allow dups
+ for (int i = 0; i < fingerIds.length; i++) {
+ if (fingerIds[i] == fingerId) return;
+ }
+ int[] newList = Arrays.copyOf(fingerIds, fingerIds.length + 1);
+ newList[fingerIds.length] = fingerId;
+ Settings.Secure.putStringForUser(res, Settings.Secure.USER_FINGERPRINT_IDS,
+ Arrays.toString(newList), userId);
+ }
+
+ public static boolean removeFingerprintIdForUser(int fingerId, ContentResolver res, int userId)
+ {
+ // FingerId 0 has special meaning. The HAL layer is supposed to remove each finger one
+ // at a time and invoke notify() for each fingerId. If we get called with 0 here, it means
+ // something bad has happened.
+ if (fingerId == 0) throw new IllegalStateException("Bad fingerId");
+
+ int[] fingerIds = getFingerprintIdsForUser(res, userId);
+ int[] resultIds = Arrays.copyOf(fingerIds, fingerIds.length);
+ int resultCount = 0;
+ for (int i = 0; i < fingerIds.length; i++) {
+ if (fingerId != fingerIds[i]) {
+ resultIds[resultCount++] = fingerIds[i];
+ }
+ }
+ if (resultCount > 0) {
+ Settings.Secure.putStringForUser(res, Settings.Secure.USER_FINGERPRINT_IDS,
+ Arrays.toString(Arrays.copyOf(resultIds, resultCount)), userId);
+ return true;
+ }
+ return false;
+ }
+
+};
+
diff --git a/core/java/android/service/fingerprint/IFingerprintService.aidl b/core/java/android/service/fingerprint/IFingerprintService.aidl
new file mode 100644
index 0000000..e92c20c
--- /dev/null
+++ b/core/java/android/service/fingerprint/IFingerprintService.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.fingerprint;
+
+import android.os.Bundle;
+import android.service.fingerprint.IFingerprintServiceReceiver;
+
+/**
+ * Communication channel from client to the fingerprint service.
+ * @hide
+ */
+interface IFingerprintService {
+ // Returns 0 if successfully started, -1 otherwise
+ int enroll(long timeout, int userId);
+
+ // Returns 0 if fingerprintId's template can be removed, -1 otherwise
+ int remove(int fingerprintId, int userId);
+
+ // Start listening for fingerprint events. This has the side effect of starting
+ // the hardware if not already started.
+ oneway void startListening(IFingerprintServiceReceiver receiver, int userId);
+
+ // Stops listening for fingerprints
+ oneway void stopListening(int userId);
+}
diff --git a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
new file mode 100644
index 0000000..4826b59
--- /dev/null
+++ b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.fingerprint;
+
+import android.os.Bundle;
+import android.os.UserHandle;
+
+/**
+ * Communication channel from the FingerprintService back to FingerprintManager.
+ * @hide
+ */
+oneway interface IFingerprintServiceReceiver {
+ void onEnrollResult(int fingerprintId, int remaining);
+ void onScanned(int fingerprintId, int confidence);
+ void onError(int error);
+ void onRemoved(int fingerprintId);
+}
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 2549fde..49a0138 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -351,18 +351,8 @@
}
ArrayMap<View, TransitionValues> endCopy =
new ArrayMap<View, TransitionValues>(endValues.viewValues);
- SparseArray<TransitionValues> endIdCopy =
- new SparseArray<TransitionValues>(endValues.idValues.size());
- for (int i = 0; i < endValues.idValues.size(); ++i) {
- int id = endValues.idValues.keyAt(i);
- endIdCopy.put(id, endValues.idValues.valueAt(i));
- }
- LongSparseArray<TransitionValues> endItemIdCopy =
- new LongSparseArray<TransitionValues>(endValues.itemIdValues.size());
- for (int i = 0; i < endValues.itemIdValues.size(); ++i) {
- long id = endValues.itemIdValues.keyAt(i);
- endItemIdCopy.put(id, endValues.itemIdValues.valueAt(i));
- }
+ SparseArray<TransitionValues> endIdCopy = endValues.idValues.clone();
+ LongSparseArray<TransitionValues> endItemIdCopy = endValues.itemIdValues.clone();
// Walk through the start values, playing everything we find
// Remove from the end set as we go
ArrayList<TransitionValues> startValuesList = new ArrayList<TransitionValues>();
@@ -376,21 +366,17 @@
}
if (!isInListView) {
int id = view.getId();
- start = startValues.viewValues.get(view) != null ?
- startValues.viewValues.get(view) : startValues.idValues.get(id);
- if (endValues.viewValues.get(view) != null) {
- end = endValues.viewValues.get(view);
+ start = startValues.viewValues.get(view);
+ end = endValues.viewValues.get(view);
+ if (end != null) {
endCopy.remove(view);
} else if (id != View.NO_ID) {
- end = endValues.idValues.get(id);
- View removeView = null;
- for (View viewToRemove : endCopy.keySet()) {
- if (viewToRemove.getId() == id) {
- removeView = viewToRemove;
- }
- }
- if (removeView != null) {
- endCopy.remove(removeView);
+ end = endIdCopy.get(id);
+ if (end == null || startValues.viewValues.containsKey(end.view)) {
+ end = null;
+ id = View.NO_ID;
+ } else {
+ endCopy.remove(end.view);
}
}
endIdCopy.remove(id);
@@ -423,36 +409,16 @@
}
}
// Now walk through the remains of the end set
+ // We've already matched everything from start to end, everything else doesn't match.
for (View view : endCopy.keySet()) {
int id = view.getId();
if (isValidTarget(view, id)) {
- TransitionValues start = startValues.viewValues.get(view) != null ?
- startValues.viewValues.get(view) : startValues.idValues.get(id);
+ TransitionValues start = null;
TransitionValues end = endCopy.get(view);
- endIdCopy.remove(id);
startValuesList.add(start);
endValuesList.add(end);
}
}
- int endIdCopySize = endIdCopy.size();
- for (int i = 0; i < endIdCopySize; ++i) {
- int id = endIdCopy.keyAt(i);
- if (isValidTarget(null, id)) {
- TransitionValues start = startValues.idValues.get(id);
- TransitionValues end = endIdCopy.get(id);
- startValuesList.add(start);
- endValuesList.add(end);
- }
- }
- int endItemIdCopySize = endItemIdCopy.size();
- for (int i = 0; i < endItemIdCopySize; ++i) {
- long id = endItemIdCopy.keyAt(i);
- // TODO: Deal with targetIDs and itemIDs
- TransitionValues start = startValues.itemIdValues.get(id);
- TransitionValues end = endItemIdCopy.get(id);
- startValuesList.add(start);
- endValuesList.add(end);
- }
ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
long minStartDelay = Long.MAX_VALUE;
int minAnimator = mAnimators.size();
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 11948b2..6c451eb 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -43,7 +43,6 @@
class GLES20Canvas extends HardwareCanvas {
// Must match modifiers used in the JNI layer
private static final int MODIFIER_NONE = 0;
- private static final int MODIFIER_SHADOW = 1;
private static final int MODIFIER_SHADER = 2;
private final boolean mOpaque;
@@ -264,27 +263,6 @@
private static native int nCallDrawGLFunction(long renderer, long drawGLFunction);
- @Override
- public int invokeFunctors(Rect dirty) {
- return nInvokeFunctors(mRenderer, dirty);
- }
-
- private static native int nInvokeFunctors(long renderer, Rect dirty);
-
- @Override
- public void detachFunctor(long functor) {
- nDetachFunctor(mRenderer, functor);
- }
-
- private static native void nDetachFunctor(long renderer, long functor);
-
- @Override
- public void attachFunctor(long functor) {
- nAttachFunctor(mRenderer, functor);
- }
-
- private static native void nAttachFunctor(long renderer, long functor);
-
///////////////////////////////////////////////////////////////////////////
// Memory
///////////////////////////////////////////////////////////////////////////
@@ -1318,12 +1296,6 @@
private int setupModifiers(Paint paint) {
int modifiers = MODIFIER_NONE;
- if (paint.hasShadow) {
- nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
- paint.shadowColor);
- modifiers |= MODIFIER_SHADOW;
- }
-
final Shader shader = paint.getShader();
if (shader != null) {
nSetupShader(mRenderer, shader.native_shader);
@@ -1336,12 +1308,6 @@
private int setupModifiers(Paint paint, int flags) {
int modifiers = MODIFIER_NONE;
- if (paint.hasShadow && (flags & MODIFIER_SHADOW) != 0) {
- nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
- paint.shadowColor);
- modifiers |= MODIFIER_SHADOW;
- }
-
final Shader shader = paint.getShader();
if (shader != null && (flags & MODIFIER_SHADER) != 0) {
nSetupShader(mRenderer, shader.native_shader);
@@ -1352,8 +1318,6 @@
}
private static native void nSetupShader(long renderer, long shader);
- private static native void nSetupShadow(long renderer, float radius,
- float dx, float dy, int color);
private static native void nResetModifiers(long renderer, int modifiers);
}
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index 97339cc..7b49006 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -168,7 +168,6 @@
private final Rect mRedrawClip = new Rect();
private final int[] mSurfaceSize = new int[2];
- private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable();
private long mDrawDelta = Long.MAX_VALUE;
@@ -654,6 +653,11 @@
}
@Override
+ void setOpaque(boolean opaque) {
+ // Not supported
+ }
+
+ @Override
boolean loadSystemProperties() {
boolean value;
boolean changed = false;
@@ -1116,22 +1120,6 @@
mName = name;
}
- class FunctorsRunnable implements Runnable {
- View.AttachInfo attachInfo;
-
- @Override
- public void run() {
- final HardwareRenderer renderer = attachInfo.mHardwareRenderer;
- if (renderer == null || !renderer.isEnabled() || renderer != GLRenderer.this) {
- return;
- }
-
- if (checkRenderContext() != SURFACE_STATE_ERROR) {
- mCanvas.invokeFunctors(mRedrawClip);
- }
- }
- }
-
@Override
void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
Rect dirty) {
@@ -1366,23 +1354,6 @@
}
}
- @Override
- void detachFunctor(long functor) {
- if (mCanvas != null) {
- mCanvas.detachFunctor(functor);
- }
- }
-
- @Override
- void attachFunctor(View.AttachInfo attachInfo, long functor) {
- if (mCanvas != null) {
- mCanvas.attachFunctor(functor);
- mFunctorsRunnable.attachInfo = attachInfo;
- attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
- attachInfo.mHandler.postDelayed(mFunctorsRunnable, 0);
- }
- }
-
/**
* Ensures the current EGL context and surface are the ones we expect.
* This method throws an IllegalStateException if invoked from a thread
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index 7ec2cc6..9568760 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -111,45 +111,6 @@
}
/**
- * Invoke all the functors who requested to be invoked during the previous frame.
- *
- * @param dirty Ignored
- *
- * @return Ignored
- *
- * @hide
- */
- public int invokeFunctors(Rect dirty) {
- return RenderNode.STATUS_DONE;
- }
-
- /**
- * Detaches the specified functor from the current functor execution queue.
- *
- * @param functor The native functor to remove from the execution queue.
- *
- * @see #invokeFunctors(android.graphics.Rect)
- * @see #callDrawGLFunction(long)
- * @see #detachFunctor(long)
- *
- * @hide
- */
- abstract void detachFunctor(long functor);
-
- /**
- * Attaches the specified functor to the current functor execution queue.
- *
- * @param functor The native functor to add to the execution queue.
- *
- * @see #invokeFunctors(android.graphics.Rect)
- * @see #callDrawGLFunction(long)
- * @see #detachFunctor(long)
- *
- * @hide
- */
- abstract void attachFunctor(long functor);
-
- /**
* Indicates that the specified layer must be updated as soon as possible.
*
* @param layer The layer to update
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index d31c79d..e366697 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -423,28 +423,6 @@
abstract boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap);
/**
- * Detaches the specified functor from the current functor execution queue.
- *
- * @param functor The native functor to remove from the execution queue.
- *
- * @see HardwareCanvas#callDrawGLFunction(int)
- * @see #attachFunctor(android.view.View.AttachInfo, long)
- */
- abstract void detachFunctor(long functor);
-
- /**
- * Schedules the specified functor in the functors execution queue.
- *
- * @param attachInfo AttachInfo tied to this renderer.
- * @param functor The native functor to insert in the execution queue.
- *
- * @see HardwareCanvas#callDrawGLFunction(int)
- * @see #detachFunctor(long)
- *
- */
- abstract void attachFunctor(View.AttachInfo attachInfo, long functor);
-
- /**
* Schedules the functor for execution in either kModeProcess or
* kModeProcessNoContext, depending on whether or not there is an EGLContext.
*
@@ -491,6 +469,11 @@
abstract void setName(String name);
/**
+ * Change the HardwareRenderer's opacity
+ */
+ abstract void setOpaque(boolean opaque);
+
+ /**
* Creates a hardware renderer using OpenGL.
*
* @param translucent True if the surface is translucent, false otherwise
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 0bf99d3..2587ba1 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -148,6 +148,11 @@
}
@Override
+ void setOpaque(boolean opaque) {
+ nSetOpaque(mNativeProxy, opaque);
+ }
+
+ @Override
int getWidth() {
return mWidth;
}
@@ -215,16 +220,6 @@
}
@Override
- void detachFunctor(long functor) {
- // no-op, we never attach functors to need to detach them
- }
-
- @Override
- void attachFunctor(AttachInfo attachInfo, long functor) {
- invokeFunctor(functor, true);
- }
-
- @Override
void invokeFunctor(long functor, boolean waitForCompletion) {
nInvokeFunctor(mNativeProxy, functor, waitForCompletion);
}
@@ -312,6 +307,7 @@
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 nSetOpaque(long nativeProxy, boolean opaque);
private static native void nSetDisplayListData(long nativeProxy, long displayList,
long newData);
private static native int nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos,
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3998c04..bef96b1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,7 +16,9 @@
package android.view;
+import android.animation.AnimatorInflater;
import android.animation.RevealAnimator;
+import android.animation.StateListAnimator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -667,6 +669,7 @@
* @attr ref android.R.styleable#View_scrollbarTrackVertical
* @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack
* @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack
+ * @attr ref android.R.styleable#View_stateListAnimator
* @attr ref android.R.styleable#View_sharedElementName
* @attr ref android.R.styleable#View_soundEffectsEnabled
* @attr ref android.R.styleable#View_tag
@@ -3258,6 +3261,11 @@
private Outline mOutline;
/**
+ * Animator that automatically runs based on state changes.
+ */
+ private StateListAnimator mStateListAnimator;
+
+ /**
* When this view has focus and the next focus is {@link #FOCUS_LEFT},
* the user may specify which view to go to next.
*/
@@ -3995,6 +4003,10 @@
case R.styleable.View_nestedScrollingEnabled:
setNestedScrollingEnabled(a.getBoolean(attr, false));
break;
+ case R.styleable.View_stateListAnimator:
+ setStateListAnimator(AnimatorInflater.loadStateListAnimator(context,
+ a.getResourceId(attr, 0)));
+ break;
}
}
@@ -6147,12 +6159,12 @@
// call into it as a fallback in case we're in a class that overrides it
// and has logic to perform.
if (fitSystemWindows(insets.getSystemWindowInsets())) {
- return insets.cloneWithSystemWindowInsetsConsumed();
+ return insets.consumeSystemWindowInsets();
}
} else {
// We were called from within a direct call to fitSystemWindows.
if (fitSystemWindowsInt(insets.getSystemWindowInsets())) {
- return insets.cloneWithSystemWindowInsetsConsumed();
+ return insets.consumeSystemWindowInsets();
}
}
return insets;
@@ -9766,6 +9778,7 @@
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -9809,6 +9822,7 @@
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -9852,6 +9866,7 @@
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -9887,6 +9902,7 @@
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -9922,6 +9938,7 @@
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -10083,6 +10100,8 @@
mPrivateFlags &= ~PFLAG_ALPHA_SET;
invalidateViewProperty(true, false);
mRenderNode.setAlpha(getFinalAlpha());
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}
}
}
@@ -10513,6 +10532,7 @@
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -10612,6 +10632,40 @@
}
/**
+ * Returns the current StateListAnimator if exists.
+ *
+ * @return StateListAnimator or null if it does not exists
+ * @see #setStateListAnimator(android.animation.StateListAnimator)
+ */
+ public StateListAnimator getStateListAnimator() {
+ return mStateListAnimator;
+ }
+
+ /**
+ * Attaches the provided StateListAnimator to this View.
+ * <p>
+ * Any previously attached StateListAnimator will be detached.
+ *
+ * @param stateListAnimator The StateListAnimator to update the view
+ * @see {@link android.animation.StateListAnimator}
+ */
+ public void setStateListAnimator(StateListAnimator stateListAnimator) {
+ if (mStateListAnimator == stateListAnimator) {
+ return;
+ }
+ if (mStateListAnimator != null) {
+ mStateListAnimator.setTarget(null);
+ }
+ mStateListAnimator = stateListAnimator;
+ if (stateListAnimator != null) {
+ stateListAnimator.setTarget(this);
+ if (isAttachedToWindow()) {
+ stateListAnimator.setState(getDrawableState());
+ }
+ }
+ }
+
+ /**
* Sets the outline of the view, which defines the shape of the shadow it
* casts.
* <p>
@@ -10661,6 +10715,7 @@
} else {
mRenderNode.setOutline(null);
}
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -10815,6 +10870,7 @@
}
invalidateParentIfNeeded();
}
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -10861,6 +10917,7 @@
}
invalidateParentIfNeeded();
}
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -12824,7 +12881,6 @@
destroyLayer(false);
cleanupDraw();
-
mCurrentAnimation = null;
}
@@ -15478,9 +15534,11 @@
/**
* This function is called whenever the state of the view changes in such
* a way that it impacts the state of drawables being shown.
- *
- * <p>Be sure to call through to the superclass when overriding this
- * function.
+ * <p>
+ * If the View has a StateListAnimator, it will also be called to run necessary state
+ * change animations.
+ * <p>
+ * Be sure to call through to the superclass when overriding this function.
*
* @see Drawable#setState(int[])
*/
@@ -15489,6 +15547,10 @@
if (d != null && d.isStateful()) {
d.setState(getDrawableState());
}
+
+ if (mStateListAnimator != null) {
+ mStateListAnimator.setState(getDrawableState());
+ }
}
/**
@@ -15633,11 +15695,17 @@
/**
* Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()}
* on all Drawable objects associated with this view.
+ * <p>
+ * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator
+ * attached to this view.
*/
public void jumpDrawablesToCurrentState() {
if (mBackground != null) {
mBackground.jumpToCurrentState();
}
+ if (mStateListAnimator != null) {
+ mStateListAnimator.jumpToCurrentState();
+ }
}
/**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 43bc0b6..4309366 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4638,6 +4638,7 @@
if (invalidate) {
invalidateViewProperty(false, false);
}
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
/**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index db87394..9b09d85 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -665,18 +665,9 @@
mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(MSG_FLUSH_LAYER_UPDATES));
}
- public void attachFunctor(long functor) {
- //noinspection SimplifiableIfStatement
- if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
- mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor);
- }
- }
-
public void detachFunctor(long functor) {
+ // TODO: Make the resize buffer some other way to not need this block
mBlockResizeBuffer = true;
- if (mAttachInfo.mHardwareRenderer != null) {
- mAttachInfo.mHardwareRenderer.detachFunctor(functor);
- }
}
public boolean invokeFunctor(long functor, boolean waitForCompletion) {
@@ -719,12 +710,15 @@
if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
&& forceHwAccelerated)) {
- // Don't enable hardware acceleration when we're not on the main thread
- if (!HardwareRenderer.sSystemRendererDisabled &&
- Looper.getMainLooper() != Looper.myLooper()) {
- Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
- + "acceleration outside of the main thread, aborting");
- return;
+ if (!HardwareRenderer.sUseRenderThread) {
+ // TODO: Delete
+ // Don't enable hardware acceleration when we're not on the main thread
+ if (!HardwareRenderer.sSystemRendererDisabled &&
+ Looper.getMainLooper() != Looper.myLooper()) {
+ Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
+ + "acceleration outside of the main thread, aborting");
+ return;
+ }
}
if (mAttachInfo.mHardwareRenderer != null) {
@@ -6174,8 +6168,10 @@
}
void changeCanvasOpacity(boolean opaque) {
- // TODO(romainguy): recreate Canvas (software or hardware) to reflect the opacity change.
Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque);
+ if (mAttachInfo.mHardwareRenderer != null) {
+ mAttachInfo.mHardwareRenderer.setOpaque(opaque);
+ }
}
class TakenSurfaceHolder extends BaseSurfaceHolder {
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 2160efe..294f472 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -29,7 +29,7 @@
* @see View.OnApplyWindowInsetsListener
* @see View#onApplyWindowInsets(WindowInsets)
*/
-public class WindowInsets {
+public final class WindowInsets {
private Rect mSystemWindowInsets;
private Rect mWindowDecorInsets;
private Rect mTempRect;
@@ -151,6 +151,7 @@
* This can include action bars, title bars, toolbars, etc.</p>
*
* @return The left window decor inset
+ * @hide pending API
*/
public int getWindowDecorInsetLeft() {
return mWindowDecorInsets.left;
@@ -164,6 +165,7 @@
* This can include action bars, title bars, toolbars, etc.</p>
*
* @return The top window decor inset
+ * @hide pending API
*/
public int getWindowDecorInsetTop() {
return mWindowDecorInsets.top;
@@ -177,6 +179,7 @@
* This can include action bars, title bars, toolbars, etc.</p>
*
* @return The right window decor inset
+ * @hide pending API
*/
public int getWindowDecorInsetRight() {
return mWindowDecorInsets.right;
@@ -190,6 +193,7 @@
* This can include action bars, title bars, toolbars, etc.</p>
*
* @return The bottom window decor inset
+ * @hide pending API
*/
public int getWindowDecorInsetBottom() {
return mWindowDecorInsets.bottom;
@@ -217,6 +221,7 @@
* This can include action bars, title bars, toolbars, etc.</p>
*
* @return true if any of the window decor inset values are nonzero
+ * @hide pending API
*/
public boolean hasWindowDecorInsets() {
return mWindowDecorInsets.left != 0 || mWindowDecorInsets.top != 0 ||
@@ -246,13 +251,28 @@
return mIsRound;
}
- public WindowInsets cloneWithSystemWindowInsetsConsumed() {
+ /**
+ * Returns a copy of this WindowInsets with the system window insets fully consumed.
+ *
+ * @return A modified copy of this WindowInsets
+ */
+ public WindowInsets consumeSystemWindowInsets() {
final WindowInsets result = new WindowInsets(this);
result.mSystemWindowInsets = new Rect(0, 0, 0, 0);
return result;
}
- public WindowInsets cloneWithSystemWindowInsetsConsumed(boolean left, boolean top,
+ /**
+ * Returns a copy of this WindowInsets with selected system window insets fully consumed.
+ *
+ * @param left true to consume the left system window inset
+ * @param top true to consume the top system window inset
+ * @param right true to consume the right system window inset
+ * @param bottom true to consume the bottom system window inset
+ * @return A modified copy of this WindowInsets
+ * @hide pending API
+ */
+ public WindowInsets consumeSystemWindowInsets(boolean left, boolean top,
boolean right, boolean bottom) {
if (left || top || right || bottom) {
final WindowInsets result = new WindowInsets(this);
@@ -265,19 +285,36 @@
return this;
}
- public WindowInsets cloneWithSystemWindowInsets(int left, int top, int right, int bottom) {
+ /**
+ * Returns a copy of this WindowInsets with selected system window insets replaced
+ * with new values.
+ *
+ * @param left New left inset in pixels
+ * @param top New top inset in pixels
+ * @param right New right inset in pixels
+ * @param bottom New bottom inset in pixels
+ * @return A modified copy of this WindowInsets
+ */
+ public WindowInsets replaceSystemWindowInsets(int left, int top,
+ int right, int bottom) {
final WindowInsets result = new WindowInsets(this);
result.mSystemWindowInsets = new Rect(left, top, right, bottom);
return result;
}
- public WindowInsets cloneWithWindowDecorInsetsConsumed() {
+ /**
+ * @hide
+ */
+ public WindowInsets consumeWindowDecorInsets() {
final WindowInsets result = new WindowInsets(this);
result.mWindowDecorInsets.set(0, 0, 0, 0);
return result;
}
- public WindowInsets cloneWithWindowDecorInsetsConsumed(boolean left, boolean top,
+ /**
+ * @hide
+ */
+ public WindowInsets consumeWindowDecorInsets(boolean left, boolean top,
boolean right, boolean bottom) {
if (left || top || right || bottom) {
final WindowInsets result = new WindowInsets(this);
@@ -290,7 +327,10 @@
return this;
}
- public WindowInsets cloneWithWindowDecorInsets(int left, int top, int right, int bottom) {
+ /**
+ * @hide
+ */
+ public WindowInsets replaceWindowDecorInsets(int left, int top, int right, int bottom) {
final WindowInsets result = new WindowInsets(this);
result.mWindowDecorInsets = new Rect(left, top, right, bottom);
return result;
diff --git a/core/java/android/webkit/PermissionRequest.java b/core/java/android/webkit/PermissionRequest.java
index 2f8850b..3e33498 100644
--- a/core/java/android/webkit/PermissionRequest.java
+++ b/core/java/android/webkit/PermissionRequest.java
@@ -19,14 +19,11 @@
import android.net.Uri;
/**
- * This class wraps a permission request, and is used to request permission for
- * the web content to access the resources.
+ * This interface defines a permission request and is used when web content
+ * requests access to protected resources.
*
- * Either {@link #grant(long) grant()} or {@link #deny()} must be called to response the
- * request, otherwise, {@link WebChromeClient#onPermissionRequest(PermissionRequest)} will
- * not be invoked again if there is other permission request in this WebView.
- *
- * @hide
+ * Either {@link #grant(long) grant()} or {@link #deny()} must be called in UI
+ * thread to respond to the request.
*/
public interface PermissionRequest {
/**
@@ -62,8 +59,6 @@
* must be equals or a subset of granted resources.
* This parameter is designed to avoid granting permission by accident
* especially when new resources are requested by web content.
- * Calling grant(getResources()) has security issue, the new permission
- * will be granted without being noticed.
*/
public void grant(long resources);
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 60cba86..d630a9a 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -304,7 +304,6 @@
* If this method isn't overridden, the permission is denied.
*
* @param request the PermissionRequest from current web content.
- * @hide
*/
public void onPermissionRequest(PermissionRequest request) {
request.deny();
@@ -314,8 +313,7 @@
* Notify the host application that the given permission request
* has been canceled. Any related UI should therefore be hidden.
*
- * @param request the PermissionRequest need be canceled.
- * @hide
+ * @param request the PermissionRequest that needs be canceled.
*/
public void onPermissionRequestCanceled(PermissionRequest request) {}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4b2b52c..91ca7b4 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1682,13 +1682,15 @@
/**
* Preauthorize the given origin to access resources.
- * This authorization only valid for this WebView instance life cycle and
+ * The authorization only valid for this WebView instance's life cycle and
* will not retained.
*
+ * In the case that an origin has had resources preauthorized, calls to
+ * {@link WebChromeClient#onPermissionRequest(PermissionRequest)} will not be
+ * made for those resources from that origin.
+ *
* @param origin the origin authorized to access resources
* @param resources the resource authorized to be accessed by origin.
- *
- * @hide
*/
public void preauthorizePermission(Uri origin, long resources) {
checkThread();
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index cde8080..99a7886 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -276,6 +276,13 @@
* @see Intent#ACTION_SEND_MULTIPLE
*/
public void setShareIntent(Intent shareIntent) {
+ if (shareIntent != null) {
+ final String action = shareIntent.getAction();
+ if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) {
+ shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
+ Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
+ }
+ }
ActivityChooserModel dataModel = ActivityChooserModel.get(mContext,
mShareHistoryFileName);
dataModel.setIntent(shareIntent);
@@ -292,7 +299,12 @@
final int itemId = item.getItemId();
Intent launchIntent = dataModel.chooseActivity(itemId);
if (launchIntent != null) {
- launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+ final String action = launchIntent.getAction();
+ if (Intent.ACTION_SEND.equals(action) ||
+ Intent.ACTION_SEND_MULTIPLE.equals(action)) {
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
+ Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
+ }
mContext.startActivity(launchIntent);
}
return true;
@@ -308,7 +320,7 @@
return;
}
if (mOnChooseActivityListener == null) {
- mOnChooseActivityListener = new ShareAcitivityChooserModelPolicy();
+ mOnChooseActivityListener = new ShareActivityChooserModelPolicy();
}
ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
dataModel.setOnChooseActivityListener(mOnChooseActivityListener);
@@ -317,7 +329,7 @@
/**
* Policy that delegates to the {@link OnShareTargetSelectedListener}, if such.
*/
- private class ShareAcitivityChooserModelPolicy implements OnChooseActivityListener {
+ private class ShareActivityChooserModelPolicy implements OnChooseActivityListener {
@Override
public boolean onChooseActivity(ActivityChooserModel host, Intent intent) {
if (mOnShareTargetSelectedListener != null) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index b91111d..8f073de 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -289,6 +289,8 @@
private Spannable.Factory mSpannableFactory = Spannable.Factory.getInstance();
private float mShadowRadius, mShadowDx, mShadowDy;
+ private int mShadowColor;
+
private boolean mPreDrawRegistered;
@@ -2755,6 +2757,7 @@
mShadowRadius = radius;
mShadowDx = dx;
mShadowDy = dy;
+ mShadowColor = color;
// Will change text clip region
if (mEditor != null) mEditor.invalidateTextDisplayList();
@@ -2804,7 +2807,7 @@
* @attr ref android.R.styleable#TextView_shadowColor
*/
public int getShadowColor() {
- return mTextPaint.shadowColor;
+ return mShadowColor;
}
/**
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 1eda373..106ac0b 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -33,6 +33,14 @@
return;
}
Intent target = (Intent)targetParcelable;
+ if (target != null) {
+ final String action = target.getAction();
+ if (Intent.ACTION_SEND.equals(action) ||
+ Intent.ACTION_SEND_MULTIPLE.equals(action)) {
+ target.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
+ Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
+ }
+ }
CharSequence title = intent.getCharSequenceExtra(Intent.EXTRA_TITLE);
if (title == null) {
title = getResources().getText(com.android.internal.R.string.chooseActivity);
@@ -43,13 +51,19 @@
initialIntents = new Intent[pa.length];
for (int i=0; i<pa.length; i++) {
if (!(pa[i] instanceof Intent)) {
- Log.w("ChooserActivity", "Initial intent #" + i
- + " not an Intent: " + pa[i]);
+ Log.w("ChooserActivity", "Initial intent #" + i + " not an Intent: " + pa[i]);
finish();
super.onCreate(null);
return;
}
- initialIntents[i] = (Intent)pa[i];
+ final Intent in = (Intent) pa[i];
+ final String action = in.getAction();
+ if (Intent.ACTION_SEND.equals(action) ||
+ Intent.ACTION_SEND_MULTIPLE.equals(action)) {
+ in.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
+ Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
+ }
+ initialIntents[i] = in;
}
}
super.onCreate(savedInstanceState, target, title, initialIntents, null, false);
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index 8cdaf91..abd1791 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -18,156 +18,122 @@
import android.app.Activity;
import android.content.ActivityNotFoundException;
+import android.content.ContentResolver;
+import android.content.Context;
import android.content.Intent;
+import android.graphics.Color;
import android.graphics.Typeface;
-import android.provider.Settings;
import android.os.Build;
import android.os.Bundle;
-import android.os.Handler;
-import android.text.method.AllCapsTransformationMethod;
+import android.provider.Settings;
+import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.AnticipateOvershootInterpolator;
-import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
-import android.widget.ImageView;
import android.widget.TextView;
public class PlatLogoActivity extends Activity {
- FrameLayout mContent;
- int mCount;
- final Handler mHandler = new Handler();
- static final int BGCOLOR = 0xffed1d24;
+ private static class Torso extends FrameLayout {
+ boolean mAnimate = false;
+ TextView mText;
+
+ public Torso(Context context) {
+ this(context, null);
+ }
+ public Torso(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+ public Torso(Context context, AttributeSet attrs, int flags) {
+ super(context, attrs, flags);
+
+ for (int i=0; i<2; i++) {
+ final View v = new View(context);
+ v.setBackgroundColor(i % 2 == 0 ? Color.BLUE : Color.RED);
+ addView(v);
+ }
+
+ mText = new TextView(context);
+ mText.setTextColor(Color.BLACK);
+ mText.setTextSize(14 /* sp */);
+ mText.setTypeface(Typeface.create("monospace", Typeface.BOLD));
+
+ addView(mText, new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.WRAP_CONTENT,
+ Gravity.BOTTOM | Gravity.LEFT
+ ));
+ }
+
+ private Runnable mRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mText.setText(String.format("android_%s.flv - build %s",
+ Build.VERSION.CODENAME,
+ Build.VERSION.INCREMENTAL));
+ final int N = getChildCount();
+ final float parentw = getMeasuredWidth();
+ final float parenth = getMeasuredHeight();
+ for (int i=0; i<N; i++) {
+ final View v = getChildAt(i);
+ if (v instanceof TextView) continue;
+
+ final int w = (int) (Math.random() * parentw);
+ final int h = (int) (Math.random() * parenth);
+ v.setLayoutParams(new FrameLayout.LayoutParams(w, h));
+
+ v.setX((float) Math.random() * (parentw - w));
+ v.setY((float) Math.random() * (parenth - h));
+ }
+
+ if (mAnimate) postDelayed(this, 1000);
+ }
+ };
+ @Override
+ protected void onAttachedToWindow() {
+ mAnimate = true;
+ post(mRunnable);
+ }
+ @Override
+ protected void onDetachedFromWindow() {
+ mAnimate = false;
+ removeCallbacks(mRunnable);
+ }
+ }
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- DisplayMetrics metrics = new DisplayMetrics();
- getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ final Torso t = new Torso(this);
+ t.setBackgroundColor(Color.WHITE);
- Typeface bold = Typeface.create("sans-serif", Typeface.BOLD);
- Typeface light = Typeface.create("sans-serif-light", Typeface.NORMAL);
+ t.getChildAt(0)
+ .setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ final ContentResolver cr = getContentResolver();
+ if (Settings.System.getLong(cr, Settings.System.EGG_MODE, 0)
+ == 0) {
+ // For posterity: the moment this user unlocked the easter egg
+ Settings.System.putLong(cr,
+ Settings.System.EGG_MODE,
+ System.currentTimeMillis());
+ }
+ try {
+ startActivity(new Intent(Intent.ACTION_MAIN)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_CLEAR_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+ .addCategory("com.android.internal.category.PLATLOGO"));
+ } catch (ActivityNotFoundException ex) {
+ android.util.Log.e("PlatLogoActivity", "Couldn't catch a break.");
+ }
+ finish();
+ return true;
+ }
+ });
- mContent = new FrameLayout(this);
- mContent.setBackgroundColor(0xC0000000);
-
- final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.WRAP_CONTENT,
- FrameLayout.LayoutParams.WRAP_CONTENT);
- lp.gravity = Gravity.CENTER;
-
- final ImageView logo = new ImageView(this);
- logo.setImageResource(com.android.internal.R.drawable.platlogo);
- logo.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
- logo.setVisibility(View.INVISIBLE);
-
- final View bg = new View(this);
- bg.setBackgroundColor(BGCOLOR);
- bg.setAlpha(0f);
-
- final TextView letter = new TextView(this);
-
- letter.setTypeface(bold);
- letter.setTextSize(300);
- letter.setTextColor(0xFFFFFFFF);
- letter.setGravity(Gravity.CENTER);
- letter.setText(String.valueOf(Build.ID).substring(0, 1));
-
- final int p = (int)(4 * metrics.density);
-
- final TextView tv = new TextView(this);
- if (light != null) tv.setTypeface(light);
- tv.setTextSize(30);
- tv.setPadding(p, p, p, p);
- tv.setTextColor(0xFFFFFFFF);
- tv.setGravity(Gravity.CENTER);
- tv.setTransformationMethod(new AllCapsTransformationMethod(this));
- tv.setText("Android " + Build.VERSION.RELEASE);
- tv.setVisibility(View.INVISIBLE);
-
- mContent.addView(bg);
- mContent.addView(letter, lp);
- mContent.addView(logo, lp);
-
- final FrameLayout.LayoutParams lp2 = new FrameLayout.LayoutParams(lp);
- lp2.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
- lp2.bottomMargin = 10*p;
-
- mContent.addView(tv, lp2);
-
- mContent.setOnClickListener(new View.OnClickListener() {
- int clicks;
- @Override
- public void onClick(View v) {
- clicks++;
- if (clicks >= 6) {
- mContent.performLongClick();
- return;
- }
- letter.animate().cancel();
- final float offset = (int)letter.getRotation() % 360;
- letter.animate()
- .rotationBy((Math.random() > 0.5f ? 360 : -360) - offset)
- .setInterpolator(new DecelerateInterpolator())
- .setDuration(700).start();
- }
- });
-
- mContent.setOnLongClickListener(new View.OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- if (logo.getVisibility() != View.VISIBLE) {
- bg.setScaleX(0.01f);
- bg.animate().alpha(1f).scaleX(1f).setStartDelay(500).start();
- letter.animate().alpha(0f).scaleY(0.5f).scaleX(0.5f)
- .rotationBy(360)
- .setInterpolator(new AccelerateInterpolator())
- .setDuration(1000)
- .start();
- logo.setAlpha(0f);
- logo.setVisibility(View.VISIBLE);
- logo.setScaleX(0.5f);
- logo.setScaleY(0.5f);
- logo.animate().alpha(1f).scaleX(1f).scaleY(1f)
- .setDuration(1000).setStartDelay(500)
- .setInterpolator(new AnticipateOvershootInterpolator())
- .start();
- tv.setAlpha(0f);
- tv.setVisibility(View.VISIBLE);
- tv.animate().alpha(1f).setDuration(1000).setStartDelay(1000).start();
- return true;
- }
- return false;
- }
- });
-
- logo.setOnLongClickListener(new View.OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- if (Settings.System.getLong(getContentResolver(), Settings.System.EGG_MODE, 0)
- == 0) {
- // For posterity: the moment this user unlocked the easter egg
- Settings.System.putLong(getContentResolver(),
- Settings.System.EGG_MODE,
- System.currentTimeMillis());
- }
- try {
- startActivity(new Intent(Intent.ACTION_MAIN)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_CLEAR_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
- .addCategory("com.android.internal.category.PLATLOGO"));
- } catch (ActivityNotFoundException ex) {
- android.util.Log.e("PlatLogoActivity", "Couldn't catch a break.");
- }
- finish();
- return true;
- }
- });
-
- setContentView(mContent);
+ setContentView(t);
}
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index d1d1a52..75feb5d 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -33,7 +33,8 @@
void animateCollapsePanels();
void setSystemUiVisibility(int vis, int mask);
void topAppWindowChanged(boolean menuVisible);
- void setImeWindowStatus(in IBinder token, int vis, int backDisposition);
+ void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher);
void setHardKeyboardStatus(boolean available, boolean enabled);
void toggleRecentApps();
void preloadRecentApps();
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index caa6b98..cf334c3 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -31,7 +31,8 @@
void setIconVisibility(String slot, boolean visible);
void removeIcon(String slot);
void topAppWindowChanged(boolean menuVisible);
- void setImeWindowStatus(in IBinder token, int vis, int backDisposition);
+ void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher);
void expandSettingsPanel();
void setCurrentUser(int newUserId);
diff --git a/core/java/com/android/internal/util/LegacyNotificationUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
similarity index 93%
rename from core/java/com/android/internal/util/LegacyNotificationUtil.java
rename to core/java/com/android/internal/util/NotificationColorUtil.java
index 0394bbc..f38cbde 100644
--- a/core/java/com/android/internal/util/LegacyNotificationUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -24,6 +24,7 @@
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.VectorDrawable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.TextAppearanceSpan;
@@ -38,21 +39,21 @@
*
* @hide
*/
-public class LegacyNotificationUtil {
+public class NotificationColorUtil {
- private static final String TAG = "LegacyNotificationUtil";
+ private static final String TAG = "NotificationColorUtil";
private static final Object sLock = new Object();
- private static LegacyNotificationUtil sInstance;
+ private static NotificationColorUtil sInstance;
private final ImageUtils mImageUtils = new ImageUtils();
private final WeakHashMap<Bitmap, Pair<Boolean, Integer>> mGrayscaleBitmapCache =
new WeakHashMap<Bitmap, Pair<Boolean, Integer>>();
- public static LegacyNotificationUtil getInstance() {
+ public static NotificationColorUtil getInstance() {
synchronized (sLock) {
if (sInstance == null) {
- sInstance = new LegacyNotificationUtil();
+ sInstance = new NotificationColorUtil();
}
return sInstance;
}
@@ -107,6 +108,9 @@
AnimationDrawable ad = (AnimationDrawable) d;
int count = ad.getNumberOfFrames();
return count > 0 && isGrayscale(ad.getFrame(0));
+ } else if (d instanceof VectorDrawable) {
+ // We just assume you're doing the right thing if using vectors
+ return true;
} else {
return false;
}
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index b380403..bc92c4a 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -46,6 +46,8 @@
public static final int BASE_WIFI_MONITOR = 0x00024000;
public static final int BASE_WIFI_MANAGER = 0x00025000;
public static final int BASE_WIFI_CONTROLLER = 0x00026000;
+ public static final int BASE_WIFI_SCANNER = 0x00027000;
+ public static final int BASE_WIFI_SCANNER_SERVICE = 0x00027100;
public static final int BASE_DHCP = 0x00030000;
public static final int BASE_DATA_CONNECTION = 0x00040000;
public static final int BASE_DATA_CONNECTION_AC = 0x00041000;
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index 674d084..bcfa036 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -35,7 +35,7 @@
public class SwipeDismissLayout extends FrameLayout {
private static final String TAG = "SwipeDismissLayout";
- private static final float DISMISS_MIN_PROGRESS = 0.6f;
+ private static final float DISMISS_MIN_DRAG_WIDTH_RATIO = .4f;
public interface OnDismissedListener {
void onDismissed(SwipeDismissLayout layout);
@@ -244,7 +244,11 @@
if (!mSwiping) {
float deltaX = ev.getRawX() - mDownX;
float deltaY = ev.getRawY() - mDownY;
- mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < mSlop * 2;
+ if ((deltaX * deltaX) + (deltaY * deltaY) > mSlop * mSlop) {
+ mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < mSlop * 2;
+ } else {
+ mSwiping = false;
+ }
}
}
@@ -254,12 +258,7 @@
mVelocityTracker.addMovement(ev);
mVelocityTracker.computeCurrentVelocity(1000);
- float velocityX = mVelocityTracker.getXVelocity();
- float absVelocityX = Math.abs(velocityX);
- float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
-
- if (deltaX > (getWidth() * DISMISS_MIN_PROGRESS) &&
- absVelocityX < mMinFlingVelocity &&
+ if (deltaX > (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO) &&
ev.getRawX() >= mLastX) {
mDismissed = true;
}
@@ -267,7 +266,7 @@
// Check if the user tried to undo this.
if (mDismissed && mSwiping) {
// Check if the user's finger is actually back
- if (deltaX < (getWidth() * DISMISS_MIN_PROGRESS)) {
+ if (deltaX < (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO)) {
mDismissed = false;
}
}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 667bf6c..51e2871 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -141,6 +141,7 @@
android_util_FileObserver.cpp \
android/opengl/poly_clip.cpp.arm \
android/opengl/util.cpp.arm \
+ android_server_FingerprintManager.cpp \
android_server_NetworkManagementSocketTagger.cpp \
android_server_Watchdog.cpp \
android_ddm_DdmHandleNativeHeap.cpp \
@@ -240,8 +241,6 @@
# <bionic_tls.h> in com_google_android_gles_jni_GLImpl.cpp
LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
-LOCAL_LDLIBS += -lpthread -ldl
-
ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
endif
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 08a88d1..22c17dd 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -33,6 +33,7 @@
#include "SkXfermode.h"
#include "unicode/uloc.h"
#include "unicode/ushape.h"
+#include "utils/Blur.h"
#include "TextLayout.h"
// temporary for debugging
@@ -776,19 +777,23 @@
env->ReleaseStringChars(text, textArray);
}
- static void setShadowLayer(JNIEnv* env, jobject jpaint, jfloat radius,
+ static void setShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat radius,
jfloat dx, jfloat dy, jint color) {
- NPE_CHECK_RETURN_VOID(env, jpaint);
-
- SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
+ SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
if (radius <= 0) {
paint->setLooper(NULL);
}
else {
- paint->setLooper(new SkBlurDrawLooper(radius, dx, dy, (SkColor)color))->unref();
+ SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius);
+ paint->setLooper(new SkBlurDrawLooper((SkColor)color, sigma, dx, dy))->unref();
}
}
+ static jboolean hasShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle) {
+ SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+ return paint->getLooper() && paint->getLooper()->asABlurShadow(NULL);
+ }
+
static int breakText(JNIEnv* env, SkPaint& paint, const jchar text[],
int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
SkPaint::TextBufferDirection tbd) {
@@ -968,7 +973,8 @@
(void*) SkPaintGlue::getStringBounds },
{"nativeGetCharArrayBounds", "(J[CIIILandroid/graphics/Rect;)V",
(void*) SkPaintGlue::getCharArrayBounds },
- {"nSetShadowLayer", "(FFFI)V", (void*)SkPaintGlue::setShadowLayer}
+ {"native_setShadowLayer", "(JFFFI)V", (void*)SkPaintGlue::setShadowLayer},
+ {"native_hasShadowLayer", "(J)Z", (void*)SkPaintGlue::hasShadowLayer}
};
static jfieldID req_fieldID(jfieldID id) {
diff --git a/core/jni/android_server_FingerprintManager.cpp b/core/jni/android_server_FingerprintManager.cpp
new file mode 100644
index 0000000..f8a1fd9
--- /dev/null
+++ b/core/jni/android_server_FingerprintManager.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Fingerprint-JNI"
+
+#include "JNIHelp.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <utils/Log.h>
+
+namespace android {
+
+static struct {
+ jclass clazz;
+ jmethodID notify;
+} gFingerprintManagerClassInfo;
+
+static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
+ return -1; // TODO
+}
+
+static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
+ return -1; // TODO
+}
+
+// ----------------------------------------------------------------------------
+
+static const JNINativeMethod g_methods[] = {
+ { "nativeEnroll", "(I)I", (void*)nativeEnroll },
+ { "nativeRemove", "(I)I", (void*)nativeRemove },
+};
+
+#define FIND_CLASS(var, className) \
+ var = env->FindClass(className); \
+ LOG_FATAL_IF(! var, "Unable to find class " className); \
+ var = jclass(env->NewGlobalRef(var));
+
+#define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
+ var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find static method" methodName);
+
+#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
+ var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find method" methodName);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+int register_android_server_FingerprintManager(JNIEnv* env) {
+ FIND_CLASS(gFingerprintManagerClassInfo.clazz,
+ "android/service/fingerprint/FingerprintManager");
+ GET_METHOD_ID(gFingerprintManagerClassInfo.notify, gFingerprintManagerClassInfo.clazz,
+ "notify", "(III)V");
+ return AndroidRuntime::registerNativeMethods(
+ env, "com/android/service/fingerprint/FingerprintManager", g_methods, NELEM(g_methods));
+}
+
+} // namespace android
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 3aa179d..fae6698 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -79,7 +79,6 @@
#define RENDERER_LOGD(...)
#endif
-#define MODIFIER_SHADOW 1
#define MODIFIER_SHADER 2
// ----------------------------------------------------------------------------
@@ -206,32 +205,6 @@
return renderer->callDrawGLFunction(functor, dirty);
}
-static void android_view_GLES20Canvas_detachFunctor(JNIEnv* env,
- jobject clazz, jlong rendererPtr, jlong functorPtr) {
- OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
- Functor* functor = reinterpret_cast<Functor*>(functorPtr);
- renderer->detachFunctor(functor);
-}
-
-static void android_view_GLES20Canvas_attachFunctor(JNIEnv* env,
- jobject clazz, jlong rendererPtr, jlong functorPtr) {
- OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
- Functor* functor = reinterpret_cast<Functor*>(functorPtr);
- renderer->attachFunctor(functor);
-}
-
-static jint android_view_GLES20Canvas_invokeFunctors(JNIEnv* env,
- jobject clazz, jlong rendererPtr, jobject dirty) {
- OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
- android::uirenderer::Rect bounds;
- status_t status = renderer->invokeFunctors(bounds);
- if (status != DrawGlInfo::kStatusDone && dirty != NULL) {
- env->CallVoidMethod(dirty, gRectClassInfo.set,
- int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom));
- }
- return status;
-}
-
// ----------------------------------------------------------------------------
// Misc
// ----------------------------------------------------------------------------
@@ -643,7 +616,6 @@
static void android_view_GLES20Canvas_resetModifiers(JNIEnv* env, jobject clazz,
jlong rendererPtr, jint modifiers) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
- if (modifiers & MODIFIER_SHADOW) renderer->resetShadow();
if (modifiers & MODIFIER_SHADER) renderer->resetShader();
}
@@ -655,12 +627,6 @@
}
-static void android_view_GLES20Canvas_setupShadow(JNIEnv* env, jobject clazz,
- jlong rendererPtr, jfloat radius, jfloat dx, jfloat dy, jint color) {
- OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
- renderer->setupShadow(radius, dx, dy, color);
-}
-
// ----------------------------------------------------------------------------
// Draw filters
// ----------------------------------------------------------------------------
@@ -1007,10 +973,6 @@
{ "nGetStencilSize", "()I", (void*) android_view_GLES20Canvas_getStencilSize },
{ "nCallDrawGLFunction", "(JJ)I", (void*) android_view_GLES20Canvas_callDrawGLFunction },
- { "nDetachFunctor", "(JJ)V", (void*) android_view_GLES20Canvas_detachFunctor },
- { "nAttachFunctor", "(JJ)V", (void*) android_view_GLES20Canvas_attachFunctor },
- { "nInvokeFunctors", "(JLandroid/graphics/Rect;)I",
- (void*) android_view_GLES20Canvas_invokeFunctors },
{ "nSave", "(JI)I", (void*) android_view_GLES20Canvas_save },
{ "nRestore", "(J)V", (void*) android_view_GLES20Canvas_restore },
@@ -1062,7 +1024,6 @@
{ "nResetModifiers", "(JI)V", (void*) android_view_GLES20Canvas_resetModifiers },
{ "nSetupShader", "(JJ)V", (void*) android_view_GLES20Canvas_setupShader },
- { "nSetupShadow", "(JFFFI)V", (void*) android_view_GLES20Canvas_setupShadow },
{ "nSetupPaintFilter", "(JII)V", (void*) android_view_GLES20Canvas_setupPaintFilter },
{ "nResetPaintFilter", "(J)V", (void*) android_view_GLES20Canvas_resetPaintFilter },
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp
index 2e8dccf..8a426ac 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android_view_GraphicBuffer.cpp
@@ -74,15 +74,10 @@
} gRectClassInfo;
static struct {
- jfieldID mFinalizer;
- jfieldID mNativeCanvas;
jfieldID mSurfaceFormat;
+ jmethodID safeCanvasSwap;
} gCanvasClassInfo;
-static struct {
- jfieldID mNativeCanvas;
-} gCanvasFinalizerClassInfo;
-
#define GET_INT(object, field) \
env->GetIntField(object, field)
@@ -146,15 +141,6 @@
// Canvas management
// ----------------------------------------------------------------------------
-static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
- jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
- SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
- GET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas));
- SET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas, (long) newCanvas);
- SET_LONG(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (long) newCanvas);
- SkSafeUnref(previousCanvas);
-}
-
static inline SkBitmap::Config convertPixelFormat(int32_t format) {
switch (format) {
case PIXEL_FORMAT_RGBA_8888:
@@ -213,7 +199,7 @@
SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer->getPixelFormat());
SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
- swapCanvasPtr(env, canvas, nativeCanvas);
+ INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
SkRect clipRect;
clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
@@ -233,7 +219,7 @@
GraphicBufferWrapper* wrapper =
reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
SkCanvas* nativeCanvas = SkNEW(SkCanvas);
- swapCanvasPtr(env, canvas, nativeCanvas);
+ INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
if (wrapper) {
status_t status = wrapper->buffer->unlock();
@@ -332,13 +318,8 @@
GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
FIND_CLASS(clazz, "android/graphics/Canvas");
- GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer",
- "Landroid/graphics/Canvas$CanvasFinalizer;");
- GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I");
-
- FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer");
- GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
+ GET_METHOD_ID(gCanvasClassInfo.safeCanvasSwap, clazz, "safeCanvasSwap", "(JZ)V");
return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index ab6c1e0..6c9d060 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -69,15 +69,10 @@
} gRectClassInfo;
static struct {
- jfieldID mFinalizer;
- jfieldID mNativeCanvas;
jfieldID mSurfaceFormat;
+ jmethodID safeCanvasSwap;
} gCanvasClassInfo;
-static struct {
- jfieldID mNativeCanvas;
-} gCanvasFinalizerClassInfo;
-
// ----------------------------------------------------------------------------
// this is just a pointer we use to pass to inc/decStrong
@@ -191,15 +186,6 @@
}
}
-static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
- jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
- SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
- env->GetLongField(canvasObj, gCanvasClassInfo.mNativeCanvas));
- env->SetLongField(canvasObj, gCanvasClassInfo.mNativeCanvas, (jlong)newCanvas);
- env->SetLongField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (jlong)newCanvas);
- SkSafeUnref(previousCanvas);
-}
-
static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {
sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
@@ -247,7 +233,7 @@
}
SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
- swapCanvasPtr(env, canvasObj, nativeCanvas);
+ env->CallVoidMethod(canvasObj, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
if (dirtyRectPtr) {
nativeCanvas->clipRect( SkRect::Make(reinterpret_cast<const SkIRect&>(dirtyRect)) );
@@ -277,7 +263,7 @@
// detach the canvas from the surface
SkCanvas* nativeCanvas = SkNEW(SkCanvas);
- swapCanvasPtr(env, canvasObj, nativeCanvas);
+ env->CallVoidMethod(canvasObj, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
// unlock surface
status_t err = surface->unlockAndPost();
@@ -388,12 +374,8 @@
gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "(J)V");
clazz = env->FindClass("android/graphics/Canvas");
- gCanvasClassInfo.mFinalizer = env->GetFieldID(clazz, "mFinalizer", "Landroid/graphics/Canvas$CanvasFinalizer;");
- gCanvasClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "J");
gCanvasClassInfo.mSurfaceFormat = env->GetFieldID(clazz, "mSurfaceFormat", "I");
-
- clazz = env->FindClass("android/graphics/Canvas$CanvasFinalizer");
- gCanvasFinalizerClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "J");
+ gCanvasClassInfo.safeCanvasSwap = env->GetMethodID(clazz, "safeCanvasSwap", "(JZ)V");
clazz = env->FindClass("android/graphics/Rect");
gRectClassInfo.left = env->GetFieldID(clazz, "left", "I");
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index 77ede33..9258543 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -44,16 +44,11 @@
} gRectClassInfo;
static struct {
- jfieldID mFinalizer;
- jfieldID mNativeCanvas;
jfieldID mSurfaceFormat;
+ jmethodID safeCanvasSwap;
} gCanvasClassInfo;
static struct {
- jfieldID mNativeCanvas;
-} gCanvasFinalizerClassInfo;
-
-static struct {
jfieldID nativeWindow;
} gTextureViewClassInfo;
@@ -125,15 +120,6 @@
}
}
-static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
- jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
- SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
- env->GetLongField(canvasObj, gCanvasClassInfo.mNativeCanvas));
- env->SetLongField(canvasObj, gCanvasClassInfo.mNativeCanvas, (jlong)newCanvas);
- env->SetLongField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (jlong)newCanvas);
- SkSafeUnref(previousCanvas);
-}
-
static jboolean android_view_TextureView_lockCanvas(JNIEnv* env, jobject,
jlong nativeWindow, jobject canvas, jobject dirtyRect) {
@@ -175,7 +161,7 @@
SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer.format);
SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
- swapCanvasPtr(env, canvas, nativeCanvas);
+ INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
SkRect clipRect;
clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
@@ -193,7 +179,7 @@
jlong nativeWindow, jobject canvas) {
SkCanvas* nativeCanvas = SkNEW(SkCanvas);
- swapCanvasPtr(env, canvas, nativeCanvas);
+ INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
if (nativeWindow) {
sp<ANativeWindow> window((ANativeWindow*) nativeWindow);
@@ -241,13 +227,8 @@
GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
FIND_CLASS(clazz, "android/graphics/Canvas");
- GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer",
- "Landroid/graphics/Canvas$CanvasFinalizer;");
- GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I");
-
- FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer");
- GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
+ GET_METHOD_ID(gCanvasClassInfo.safeCanvasSwap, clazz, "safeCanvasSwap", "(JZ)V");
FIND_CLASS(clazz, "android/view/TextureView");
GET_FIELD_ID(gTextureViewClassInfo.nativeWindow, clazz, "mNativeWindow", "J");
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 6ff28e3..cdd036e 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -197,6 +197,12 @@
proxy->setup(width, height);
}
+static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jboolean opaque) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->setOpaque(opaque);
+}
+
static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
jlong proxyPtr, jlong frameTimeNanos, jint dirtyLeft, jint dirtyTop,
jint dirtyRight, jint dirtyBottom) {
@@ -279,6 +285,7 @@
{ "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 },
+ { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
{ "nSyncAndDrawFrame", "(JJIIII)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
{ "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface },
{ "nInvokeFunctor", "(JJZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 241500a..cdb77f1 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1295,10 +1295,9 @@
<!-- @hide Fuller form of {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
that removes restrictions on where broadcasts can be sent and allows other
types of interactions. -->
- <!-- TODO: Remove the system protection level.-->
<permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
- android:protectionLevel="signature|system"
+ android:protectionLevel="signature"
android:label="@string/permlab_interactAcrossUsersFull"
android:description="@string/permdesc_interactAcrossUsersFull" />
diff --git a/core/res/res/anim/button_state_list_anim_quantum.xml b/core/res/res/anim/button_state_list_anim_quantum.xml
new file mode 100644
index 0000000..01989a4
--- /dev/null
+++ b/core/res/res/anim/button_state_list_anim_quantum.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:state_enabled="true">
+ <set>
+ <objectAnimator android:propertyName="translationZ"
+ android:duration="@integer/button_pressed_animation_duration"
+ android:valueTo="@dimen/button_pressed_z"
+ android:valueType="floatType"/>
+ </set>
+ </item>
+ <!-- base state -->
+ <item>
+ <set>
+ <objectAnimator android:propertyName="translationZ"
+ android:duration="@integer/button_pressed_animation_duration"
+ android:valueTo="0"
+ android:valueType="floatType"/>
+ </set>
+ </item>
+</selector>
\ No newline at end of file
diff --git a/core/res/res/drawable-hdpi/stat_sys_adb_am.png b/core/res/res/drawable-hdpi/stat_sys_adb_am.png
deleted file mode 100644
index dad614c..0000000
--- a/core/res/res/drawable-hdpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_sys_adb_am.png b/core/res/res/drawable-ldpi/stat_sys_adb_am.png
deleted file mode 100644
index 0171adb..0000000
--- a/core/res/res/drawable-ldpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_adb_am.png b/core/res/res/drawable-mdpi/stat_sys_adb_am.png
deleted file mode 100644
index 5482f34..0000000
--- a/core/res/res/drawable-mdpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.png b/core/res/res/drawable-nodpi/platlogo.png
deleted file mode 100644
index 6351c2d..0000000
--- a/core/res/res/drawable-nodpi/platlogo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml
new file mode 100644
index 0000000..8eb00fa
--- /dev/null
+++ b/core/res/res/drawable-nodpi/platlogo.xml
@@ -0,0 +1,39 @@
+<!--
+ 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size android:width="400dp" android:height="400dp"/>
+
+ <viewport android:viewportHeight="25" android:viewportWidth="25" />
+
+ <group>
+ <path
+ android:name="shadow"
+ android:pathData="m12,2.5 a11,11 0 1,0 1,0
+ M6.5,7.5
+ l5,0 l0,7 l7,0 l0,5 l-12,0 z"
+ android:fill="#40000000"
+ />
+ <path
+ android:name="circle-L-ranch"
+ android:pathData="m12,1.5 a11,11 0 1,0 1,0
+ M6.5,6.5
+ l5,0 l0,7 l7,0 l0,5 l-12,0 z"
+ android:fill="#FFFFFF40"
+ />
+ </group>
+</vector>
+
+
diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml
new file mode 100644
index 0000000..37df348
--- /dev/null
+++ b/core/res/res/drawable-nodpi/stat_sys_adb.xml
@@ -0,0 +1,30 @@
+<!--
+ 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size android:width="25dp" android:height="25dp"/>
+
+ <viewport android:viewportHeight="25" android:viewportWidth="25" />
+
+ <group>
+ <path
+ android:name="adb"
+ android:pathData="m3,3l8,0l0,11l11,0l0,8l-18,0z"
+ android:fill="#FFFFFFFF"
+ />
+ </group>
+</vector>
+
+
diff --git a/core/res/res/drawable-xhdpi/stat_sys_adb_am.png b/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
deleted file mode 100644
index e53f498..0000000
--- a/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png b/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
deleted file mode 100644
index d6018dd..0000000
--- a/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/btn_check_quantum_anim.xml b/core/res/res/drawable/btn_check_quantum_anim.xml
index 0600522..4b329ad 100644
--- a/core/res/res/drawable/btn_check_quantum_anim.xml
+++ b/core/res/res/drawable/btn_check_quantum_anim.xml
@@ -14,7 +14,6 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:trigger="state_checked"
android:versionCode="1" >
<size
@@ -27,53 +26,8 @@
<group>
<path
- android:name="box1"
- android:pathData="M 240,80 L 240,240 L 80,240 L 80,80 L 240,80 L 240,80 z"
- android:stroke="?attr/colorControlNormal"
- android:strokeWidth="20"
- android:strokeLineCap="round"
- android:strokeLineJoin="round" />
- </group>
- <group>
- <path
- android:name="box2"
- android:pathData="M 160,200 L 160,240 L 120,240 L 120,200 L 160,200 L 160,200 z"
- android:stroke="?attr/colorControlNormal"
- android:strokeWidth="10"
- android:strokeLineCap="round"
- android:strokeLineJoin="round" />
- </group>
- <group>
- <path
- android:name="box3"
- android:pathData="M 160,216.5 L 143.5,240 L 120,223.5 L 136.5,200 L 160,216.5 L 160,216.5 z"
- android:rotation="35"
- android:pivotX="140"
- android:pivotY="220"
- android:fill="?attr/colorControlNormal"
- android:stroke="?attr/colorControlNormal"
- android:strokeWidth="5"
- android:strokeLineCap="round"
- android:strokeLineJoin="round" />
- </group>
- <group>
- <path
- android:name="box4"
- android:pathData="M 160,216.5 L 143.5,240 L 120,223.5 L 136.5,200 L 160,216.5 L 160,216.5 z"
- android:fill="?attr/colorControlActivated"
- android:stroke="?attr/colorControlActivated"
- android:strokeLineCap="round"
- android:strokeLineJoin="round" />
- </group>
- <group>
- <path
android:name="check"
android:pathData="M 232.1,80.6 L 248.5,92.1 L 145.2,239.5 L 71.5,187.8 L 83,171.5 L 140.3,211.7 z"
android:fill="?attr/colorControlActivated" />
</group>
-
- <animation
- android:durations="300,100,0,300"
- android:sequence="box1,box2,box3,box4,check" />
-
</vector>
diff --git a/core/res/res/drawable/notification_icon_legacy_bg.xml b/core/res/res/drawable/notification_icon_legacy_bg.xml
index 4ac67c3..cc5755d 100644
--- a/core/res/res/drawable/notification_icon_legacy_bg.xml
+++ b/core/res/res/drawable/notification_icon_legacy_bg.xml
@@ -18,5 +18,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
- android:color="@color/notification_icon_legacy_bg_color"/>
+ android:color="@color/notification_icon_bg_color"/>
</shape>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 4358dd3..790567e 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -31,11 +31,11 @@
<string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> dag <xliff:g id="HOURS">%2$d</xliff:g> uur"</string>
<string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> dag <xliff:g id="HOURS">%2$d</xliff:g> uur"</string>
<string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> uur"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> uur <xliff:g id="MINUTES">%2$d</xliff:g> minute"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> uur <xliff:g id="MINUTES">%2$d</xliff:g> minuut"</string>
+ <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> u. <xliff:g id="MINUTES">%2$d</xliff:g> min."</string>
+ <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> u. <xliff:g id="MINUTES">%2$d</xliff:g> min."</string>
<string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> minute"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> minuut <xliff:g id="SECONDS">%2$d</xliff:g> sekondes"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> minuut <xliff:g id="SECONDS">%2$d</xliff:g> sekond"</string>
+ <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min. <xliff:g id="SECONDS">%2$d</xliff:g> s."</string>
+ <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min. <xliff:g id="SECONDS">%2$d</xliff:g> s."</string>
<string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sekondes"</string>
<string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sekonde"</string>
<string name="untitled" msgid="4638956954852782576">"<Titelloos>"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index dbc0d43..66b4a90 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -741,7 +741,7 @@
<string name="policylab_expirePassword" msgid="885279151847254056">"تنظیم زمان انقضای رمز ورود قفل صفحه"</string>
<string name="policydesc_expirePassword" msgid="1729725226314691591">"کنترل کنید چند وقت یک بار باید گذرواژه صفحه قفل عوض شود."</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"تنظیم رمزگذاری حافظه"</string>
- <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"باید اطلاعات ذخیره شده برنامه رمزگذاری شود."</string>
+ <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"اطلاعات ذخیره شده برنامه باید رمزگذاری شود."</string>
<string name="policylab_disableCamera" msgid="6395301023152297826">"غیر فعال کردن دوربین ها"</string>
<string name="policydesc_disableCamera" msgid="2306349042834754597">"جلوگیری از استفاده از همه دوربینهای دستگاه."</string>
<string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"غیرفعال کردن ویژگیها در محافظ کلید"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 03dfb12..eb2540d 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -188,10 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-järjestelmä"</string>
- <!-- no translation found for user_owner_label (2804351898001038951) -->
- <skip />
- <!-- no translation found for managed_profile_label (6260850669674791528) -->
- <skip />
+ <string name="user_owner_label" msgid="2804351898001038951">"Henkilökohtainen"</string>
+ <string name="managed_profile_label" msgid="6260850669674791528">"Työ"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Maksulliset palvelut"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Suorita mahdollisesti maksullisia toimintoja."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Omat viestit"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index ea9ffb3..751327b 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -188,10 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Mod selamat"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
- <!-- no translation found for user_owner_label (2804351898001038951) -->
- <skip />
- <!-- no translation found for managed_profile_label (6260850669674791528) -->
- <skip />
+ <string name="user_owner_label" msgid="2804351898001038951">"Peribadi"</string>
+ <string name="managed_profile_label" msgid="6260850669674791528">"Tempat Kerja"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Perkhidmatan yang anda perlu bayar"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Melakukan perkara yang boleh mengenakan bayaran kepada anda."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Mesej anda"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index ecec099..f9b9fd2 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -31,13 +31,13 @@
<string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> dia <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
<string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> dia <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
<string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> horas"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min."</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min."</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min."</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min. <xliff:g id="SECONDS">%2$d</xliff:g> seg."</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min. <xliff:g id="SECONDS">%2$d</xliff:g> seg."</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> seg."</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> seg."</string>
+ <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
+ <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
+ <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
+ <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> seg"</string>
+ <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> seg"</string>
+ <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> seg"</string>
+ <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> seg"</string>
<string name="untitled" msgid="4638956954852782576">"<Sem nome>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 93107ca..be2ed29 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -188,10 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <!-- no translation found for user_owner_label (2804351898001038951) -->
- <skip />
- <!-- no translation found for managed_profile_label (6260850669674791528) -->
- <skip />
+ <string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
+ <string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Serviços que geram gastos"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Faça coisas que podem custar dinheiro."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Suas mensagens"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 568e093..33a5a81 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -188,10 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"˃999"</string>
<string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistemul Android"</string>
- <!-- no translation found for user_owner_label (2804351898001038951) -->
- <skip />
- <!-- no translation found for managed_profile_label (6260850669674791528) -->
- <skip />
+ <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
+ <string name="managed_profile_label" msgid="6260850669674791528">"Serviciu"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servicii cu plată"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Efectuează acţiuni care sunt cu plată."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Mesajele dvs."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 8a0141a..c7c5a08 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -34,10 +34,10 @@
<string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> ч. <xliff:g id="MINUTES">%2$d</xliff:g> мин."</string>
<string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> ч. <xliff:g id="MINUTES">%2$d</xliff:g> мин."</string>
<string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> мин."</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> мин. <xliff:g id="SECONDS">%2$d</xliff:g> с."</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> мин. <xliff:g id="SECONDS">%2$d</xliff:g> с."</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> с."</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> с."</string>
+ <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> мин. <xliff:g id="SECONDS">%2$d</xliff:g> с"</string>
+ <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> мин. <xliff:g id="SECONDS">%2$d</xliff:g> с"</string>
+ <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> с"</string>
+ <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> с"</string>
<string name="untitled" msgid="4638956954852782576">"<Без названия>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"..."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 793e5bf..3476692 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -188,10 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
- <!-- no translation found for user_owner_label (2804351898001038951) -->
- <skip />
- <!-- no translation found for managed_profile_label (6260850669674791528) -->
- <skip />
+ <string name="user_owner_label" msgid="2804351898001038951">"个人"</string>
+ <string name="managed_profile_label" msgid="6260850669674791528">"企业"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"需要您付费的服务"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"执行可能需要您付费的操作。"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"您的信息"</string>
@@ -716,8 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"允许该应用检索、检查并清除通知,包括其他应用发布的通知。"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"绑定到通知侦听器服务"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允许应用绑定到通知侦听器服务的顶级接口(普通应用绝不需要此权限)。"</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"绑定到条件提供方服务"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允许应用绑定到条件提供方服务的顶级接口。普通应用绝不需要此权限。"</string>
+ <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"绑定到条件提供程序服务"</string>
+ <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允许应用绑定到条件提供程序服务的顶级接口。普通应用绝不需要此权限。"</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"调用运营商提供的配置应用"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允许应用调用运营商提供的配置应用。普通应用绝不需要此权限。"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"监听网络状况的观测信息"</string>
@@ -1388,7 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"壁纸"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"更改壁纸"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"通知侦听器"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"条件提供方"</string>
+ <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"条件提供程序"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN 已激活"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"“<xliff:g id="APP">%s</xliff:g>”已激活 VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"触摸可管理网络。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 547ca27..4a67538 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1169,7 +1169,7 @@
<string name="whichHomeApplication" msgid="4616420172727326782">"選取主螢幕應用程式"</string>
<string name="alwaysUse" msgid="4583018368000610438">"設為預設應用程式。"</string>
<string name="clearDefaultHintMsg" msgid="3252584689512077257">"前往 [系統設定] > [應用程式] > [下載] 清除預設值。"</string>
- <string name="chooseActivity" msgid="7486876147751803333">"選擇一種動作"</string>
+ <string name="chooseActivity" msgid="7486876147751803333">"選擇分享方式"</string>
<string name="chooseUsbActivity" msgid="6894748416073583509">"選取要以 USB 裝置存取的應用程式"</string>
<string name="noApplications" msgid="2991814273936504689">"沒有應用程式可執行這項操作。"</string>
<string name="aerr_title" msgid="1905800560317137752"></string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0326e18..d9473ec 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2364,6 +2364,9 @@
<!-- Specifies that this view should permit nested scrolling within a compatible
ancestor view. -->
<attr name="nestedScrollingEnabled" format="boolean" />
+
+ <!-- Sets the state-based animator for the View. -->
+ <attr name="stateListAnimator" format="reference"/>
</declare-styleable>
<!-- Attributes that can be assigned to a tag for a particular View. -->
@@ -4255,6 +4258,11 @@
<attr name="drawable" format="reference" />
</declare-styleable>
+ <!-- Attributes that can be assigned to a StateListAnimator item. -->
+ <declare-styleable name="StateListAnimatorItem">
+ <attr name="animation"/>
+ </declare-styleable>
+
<!-- Drawable used to render a geometric shape, with a gradient or a solid color. -->
<declare-styleable name="GradientDrawable">
<!-- Indicates whether the drawable should intially be visible. -->
@@ -4652,18 +4660,6 @@
<!-- Drawable used to draw Vector Drawables. -->
<declare-styleable name="VectorDrawable">
- <!-- What event triggers the animation -->
- <attr name="trigger" format="enum">
- <enum name="state_pressed" value="1" />
- <enum name="state_focused" value="2" />
- <enum name="state_hovered" value="3" />
- <enum name="state_selected" value="4" />
- <enum name="state_checkable" value="5" />
- <enum name="state_checked" value="6" />
- <enum name="state_enabled" value="7" />
- <enum name="state_activated" value="8" />
- <enum name="state_window_focused" value="9" />
- </attr>
<attr name="versionCode" />
</declare-styleable>
@@ -4683,42 +4679,6 @@
<attr name="height" />
</declare-styleable>
- <!-- Define the animations of drawable -->
- <declare-styleable name="VectorDrawableAnimation">
- <!-- Configures this animation sequence between the named paths -->
- <attr name="sequence" format="string"/>
- <!-- Limits an animation to only interpolate the selected variable -->
- <attr name="limitTo" format="enum">
- <enum name="unlimited" value="0"/>
- <enum name="path" value="1"/>
- <enum name="rotation" value="2"/>
- <enum name="trimPathStart" value="3"/>
- <enum name="trimPathEnd" value="4"/>
- <enum name="trimPathOffset" value="5"/>
- </attr>
- <!-- Number of times to loop this aspect of the animation -->
- <attr name="repeatCount"/>
- <!-- A list of times in milliseconds to transision from on path to another.
- List must contain one less than the number of named paths
- e.g. given sequence="A,B,C,D" durations="100,0,100" implies 100ms for the
- "A" to "B" transision instantanious switch to "C" and 100ms for "C" to "D". -->
- <attr name="durations" format="string" />
- <!-- The delay before stating this aspect of the animation in milli seconds -->
- <attr name="startDelay" />
- <!-- when repeating how does it repeat back and forth or a to b -->
- <attr name="repeatStyle" format="enum">
- <enum name="forward" value="0"/>
- <enum name="reverse" value="1"/>[]
- </attr>
- <!-- how does the animation progress from start to finish -->
- <attr name="animate" format="enum">
- <enum name="linear" value="0"/>
- <enum name="easeIn" value="1"/>
- <enum name="easeOut" value="2"/>
- <enum name="easeInOut" value="3"/>
- </attr>
- </declare-styleable>
-
<!-- Defines the path used in Vector Drawables. -->
<declare-styleable name="VectorDrawablePath">
<!-- The Name of this path -->
@@ -4763,26 +4723,6 @@
</attr>
<!-- sets the Miter limit for a stroked path -->
<attr name="strokeMiterLimit" format="float"/>
- <!-- sets a condition to be met to draw path -->
- <attr name="state_pressed" />
- <!-- sets a condition to be met to draw path -->
- <attr name="state_focused" />
- <!-- sets a condition to be met to draw path -->
- <attr name="state_selected" />
- <!-- sets a condition to be met to draw path -->
- <attr name="state_window_focused" />
- <!-- sets a condition to be met to draw path -->
- <attr name="state_enabled" />
- <!-- sets a condition to be met to draw path -->
- <attr name="state_activated" />
- <!-- sets a condition to be met to draw path -->
- <attr name="state_accelerated" />
- <!-- sets a condition to be met to draw path -->
- <attr name="state_hovered" />
- <!-- sets a condition to be met to draw path -->
- <attr name="state_checked" />
- <!-- sets a condition to be met to draw path -->
- <attr name="state_checkable" />
</declare-styleable>
<!-- ========================== -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index cce4dbd..b1f256e 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -885,6 +885,47 @@
be passed a persistable Bundle in their Intent.extras. -->
<attr name="persistable" format="boolean" />
+ <!-- Specify whether this activity should always be launched in doc-centric mode. For
+ values other than <code>none</code> the activity must be defined with
+ {@link android.R.attr#launchMode} <code>standard</code> or <code>singleTop</code>.
+ This attribute can be overridden by {@link
+ android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}.
+
+ <p>If this attribute is not specified, <code>none</code> will be used.
+ Note that this launch behavior can be changed in some ways at runtime
+ through the {@link android.content.Intent} flags
+ {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}. -->
+ <attr name="documentLaunchMode">
+ <!-- The default mode, which will create a new task only when
+ {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK
+ Intent.FLAG_ACTIVITY_NEW_TASK} is set. -->
+ <enum name="none" value="0" />
+ <!-- All tasks will be searched for a matching Intent. If one is found
+ That task will cleared and restarted with the root activity receiving a call
+ to {@link android.app.Activity#onNewIntent Activity.onNewIntent}. If no
+ such task is found a new task will be created.
+ This is the equivalent of with {@link
+ android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT Intent.FLAG_ACTIVITY_NEW_DOCUMENT}
+ without {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
+ Intent.FLAG_ACTIVITY_MULTIPLE_TASK}. -->
+ <enum name="intoExisting" value="1" />
+ <!-- A new task rooted at this activity will be created.
+ This is the equivalent of with {@link
+ android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT Intent.FLAG_ACTIVITY_NEW_DOCUMENT}
+ paired with {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
+ Intent.FLAG_ACTIVITY_MULTIPLE_TASK}. -->
+ <enum name="always" value="2" />
+ </attr>
+
+ <!-- Tasks launched by activities with this attribute will remain in the recent task
+ list until the last activity in the task is completed. When that happens the task
+ will be automatically removed from the recent task list.
+
+ This attribute is the equivalent of {@link
+ android.content.Intent#FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS
+ Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS} -->
+ <attr name="autoRemoveFromRecents" format="boolean" />
+
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
describing the contents of an Android package (.apk) file. One
@@ -1549,6 +1590,8 @@
<attr name="primaryUserOnly" format="boolean" />
<attr name="persistable" />
<attr name="allowEmbedded" />
+ <attr name="documentLaunchMode" />
+ <attr name="autoRemoveFromRecents" />
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 761170d..7d3fb44 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -123,7 +123,7 @@
<drawable name="notification_template_icon_bg">#3333B5E5</drawable>
<drawable name="notification_template_icon_low_bg">#0cffffff</drawable>
- <color name="notification_icon_legacy_bg_color">#ff4285F4</color>
+ <color name="notification_icon_bg_color">#ffa3a3a3</color>
<color name="notification_action_legacy_color_filter">#ff555555</color>
<!-- Keyguard colors -->
diff --git a/core/res/res/values/dimens_quantum.xml b/core/res/res/values/dimens_quantum.xml
index cebee12..53e97fd 100644
--- a/core/res/res/values/dimens_quantum.xml
+++ b/core/res/res/values/dimens_quantum.xml
@@ -49,4 +49,7 @@
<dimen name="floating_window_z">16dp</dimen>
<dimen name="floating_window_margin">32dp</dimen>
+
+ <!-- the amount of elevation for pressed button state-->
+ <dimen name="button_pressed_z">2dp</dimen>
</resources>
diff --git a/core/res/res/values/integers.xml b/core/res/res/values/integers.xml
index dc90bbf..e6748c4 100644
--- a/core/res/res/values/integers.xml
+++ b/core/res/res/values/integers.xml
@@ -19,4 +19,5 @@
<resources>
<integer name="kg_carousel_angle">75</integer>
<integer name="kg_glowpad_rotation_offset">0</integer>
+ <integer name="button_pressed_animation_duration">100</integer>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e88a6ee..4e584c0 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2116,7 +2116,6 @@
<public type="attr" name="controlY2" />
<public type="attr" name="sharedElementName" />
<public type="attr" name="transitionGroup" />
- <public type="attr" name="trigger" />
<public type="attr" name="viewportWidth" />
<public type="attr" name="viewportHeight" />
<public type="attr" name="fillOpacity" />
@@ -2125,17 +2124,12 @@
<public type="attr" name="stroke" />
<public type="attr" name="strokeOpacity" />
<public type="attr" name="strokeWidth" />
- <public type="attr" name="durations" />
- <public type="attr" name="sequence" />
- <public type="attr" name="repeatStyle" />
<public type="attr" name="trimPathStart" />
<public type="attr" name="trimPathEnd" />
<public type="attr" name="trimPathOffset" />
<public type="attr" name="strokeLineCap" />
<public type="attr" name="strokeLineJoin" />
<public type="attr" name="clipToPath" />
- <public type="attr" name="animate" />
- <public type="attr" name="limitTo" />
<public type="attr" name="requiredForProfile"/>
<public type="attr" name="pinned" />
<public type="attr" name="colorControlNormal" />
@@ -2169,6 +2163,9 @@
<public type="attr" name="excludeClass" />
<public type="attr" name="hideOnContentScroll" />
<public type="attr" name="actionOverflowMenuStyle" />
+ <public type="attr" name="documentLaunchMode" />
+ <public type="attr" name="autoRemoveFromRecents" />
+ <public type="attr" name="stateListAnimator" />
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index 01c3017..88a2a9f 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -364,6 +364,7 @@
<item name="textColor">?attr/textColorPrimary</item>
<item name="minHeight">48dip</item>
<item name="minWidth">96dip</item>
+ <item name="stateListAnimator">@anim/button_state_list_anim_quantum</item>
</style>
<!-- Small bordered ink button -->
@@ -375,6 +376,7 @@
<!-- Borderless ink button -->
<style name="Widget.Quantum.Button.Borderless">
<item name="background">@drawable/btn_borderless_quantum</item>
+ <item name="stateListAnimator">@null</item>
</style>
<!-- Small borderless ink button -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a8a4b51..2bf72e8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1664,6 +1664,7 @@
<java-symbol type="layout" name="notification_template_quantum_big_text" />
<java-symbol type="layout" name="notification_template_quantum_inbox" />
<java-symbol type="color" name="notification_action_legacy_color_filter" />
+ <java-symbol type="color" name="notification_icon_bg_color" />
<java-symbol type="drawable" name="notification_icon_legacy_bg_inset" />
<java-symbol type="drawable" name="notification_quantum_bg_dim" />
<java-symbol type="drawable" name="notification_quantum_bg" />
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index 39c8beb..768fd9a 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -123,7 +123,7 @@
<item name="listSeparatorTextViewStyle">@style/Widget.Quantum.TextView.ListSeparator</item>
<item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum</item>
- <item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum_anim</item>
+ <item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum</item>
<item name="listChoiceBackgroundIndicator">@drawable/list_selector_quantum</item>
@@ -467,7 +467,7 @@
<item name="listSeparatorTextViewStyle">@style/Widget.Quantum.Light.TextView.ListSeparator</item>
<item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum</item>
- <item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum_anim</item>
+ <item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum</item>
<item name="listChoiceBackgroundIndicator">@drawable/list_selector_quantum</item>
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java
new file mode 100644
index 0000000..0f3ea0e
--- /dev/null
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.os.ParcelUuid;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit test cases for {@link BluetoothUuid}.
+ * <p>
+ * To run this test, use adb shell am instrument -e class 'android.bluetooth.BluetoothUuidTest' -w
+ * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner'
+ */
+public class BluetoothUuidTest extends TestCase {
+
+ @SmallTest
+ public void testUuidParser() {
+ byte[] uuid16 = new byte[] {
+ 0x0B, 0x11 };
+ assertEquals(ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"),
+ BluetoothUuid.parseUuidFrom(uuid16));
+
+ byte[] uuid32 = new byte[] {
+ 0x0B, 0x11, 0x33, (byte) 0xFE };
+ assertEquals(ParcelUuid.fromString("FE33110B-0000-1000-8000-00805F9B34FB"),
+ BluetoothUuid.parseUuidFrom(uuid32));
+
+ byte[] uuid128 = new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, (byte) 0xFF };
+ assertEquals(ParcelUuid.fromString("FF0F0E0D-0C0B-0A09-0807-0060504030201"),
+ BluetoothUuid.parseUuidFrom(uuid128));
+ }
+}
diff --git a/core/tests/coretests/res/anim/reset_state_anim.xml b/core/tests/coretests/res/anim/reset_state_anim.xml
new file mode 100644
index 0000000..918d0a3
--- /dev/null
+++ b/core/tests/coretests/res/anim/reset_state_anim.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+ <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+ <objectAnimator android:propertyName="z" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+</set>
\ No newline at end of file
diff --git a/core/tests/coretests/res/anim/test_state_anim.xml b/core/tests/coretests/res/anim/test_state_anim.xml
new file mode 100644
index 0000000..9e08f68
--- /dev/null
+++ b/core/tests/coretests/res/anim/test_state_anim.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true">
+ <set>
+ <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="10" android:valueType="floatType"/>
+ <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="20" android:valueType="floatType"/>
+ <objectAnimator android:propertyName="z" android:duration="100" android:valueTo="20" android:valueType="floatType"/>
+ </set>
+ </item>
+ <item android:state_enabled="true" android:state_pressed="false">
+ <set>
+ <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+ <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+ <objectAnimator android:propertyName="z" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+ </set>
+ </item>
+ <!-- base state-->
+ <item android:animation="@anim/reset_state_anim"/>
+</selector>
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/animation/StateListAnimatorTest.java b/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
new file mode 100644
index 0000000..38df78d
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
@@ -0,0 +1,102 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+package android.animation;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.util.StateSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.frameworks.coretests.R;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+
+public class StateListAnimatorTest extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
+
+ public StateListAnimatorTest() {
+ super(BasicAnimatorActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ public void testInflateFromAnimator() throws Exception {
+ StateListAnimator stateListAnimator = AnimatorInflater
+ .loadStateListAnimator(getActivity(), R.anim.test_state_anim);
+ assertNotNull("A state list animator should be returned", stateListAnimator);
+ assertEquals("State list animator should have three items", 3,
+ stateListAnimator.getTuples().size());
+ }
+
+ @UiThreadTest
+ public void testAttachDetach() throws Exception {
+ View view = new View(getActivity());
+ final AtomicInteger setStateCount = new AtomicInteger(0);
+ StateListAnimator stateListAnimator = new StateListAnimator() {
+ @Override
+ public void setState(int[] state) {
+ setStateCount.incrementAndGet();
+ super.setState(state);
+ }
+ };
+ view.setStateListAnimator(stateListAnimator);
+ assertNotNull("State list animator should have a reference to view even if it is detached",
+ stateListAnimator.getTarget());
+ ViewGroup viewGroup = (ViewGroup) getActivity().findViewById(android.R.id.content);
+ int preSetStateCount = setStateCount.get();
+ viewGroup.addView(view);
+ assertTrue("When view is attached, state list drawable's setState should be called",
+ preSetStateCount < setStateCount.get());
+
+ StateListAnimator stateListAnimator2 = new StateListAnimator();
+ view.setStateListAnimator(stateListAnimator2);
+ assertNull("When a new state list animator is assigned, previous one should be detached",
+ stateListAnimator.getTarget());
+ assertNull("Any running animator should be removed on detach",
+ stateListAnimator.getRunningAnimator());
+ assertEquals("The new state list animator should be attached to the view",
+ view, stateListAnimator2.getTarget());
+ viewGroup.removeView(view);
+ assertNotNull("When view is detached from window, state list animator should still keep the"
+ + " reference",
+ stateListAnimator2.getTarget());
+ }
+
+ public void testStateListLoading() throws InterruptedException {
+ StateListAnimator stateListAnimator = AnimatorInflater
+ .loadStateListAnimator(getActivity(), R.anim.test_state_anim);
+ assertNotNull("A state list animator should be returned", stateListAnimator);
+ assertEquals("Steate list animator should have two items", 3,
+ stateListAnimator.getTuples().size());
+ StateListAnimator.Tuple tuple1 = stateListAnimator.getTuples().get(0);
+ assertEquals("first tuple should have one state", 1, tuple1.getSpecs().length);
+ assertEquals("first spec in tuple 1 should be pressed",
+ com.android.internal.R.attr.state_pressed, tuple1.getSpecs()[0]);
+
+ StateListAnimator.Tuple tuple2 = stateListAnimator.getTuples().get(1);
+ assertEquals("Second tuple should have two specs", 2, tuple2.getSpecs().length);
+ assertTrue("Tuple two should match the expected state",
+ StateSet.stateSetMatches(tuple2.getSpecs(),
+ new int[]{-com.android.internal.R.attr.state_pressed,
+ com.android.internal.R.attr.state_enabled}));
+ }
+}
diff --git a/graphics/java/android/graphics/Camera.java b/graphics/java/android/graphics/Camera.java
index c263a84..a40085b 100644
--- a/graphics/java/android/graphics/Camera.java
+++ b/graphics/java/android/graphics/Camera.java
@@ -154,7 +154,7 @@
getMatrix(mMatrix);
canvas.concat(mMatrix);
} else {
- nativeApplyToCanvas(canvas.mNativeCanvas);
+ nativeApplyToCanvas(canvas.getNativeCanvas());
}
}
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index ae3eae1..5b18623 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -39,8 +39,12 @@
public class Canvas {
// assigned in constructors or setBitmap, freed in finalizer
+ private long mNativeCanvas;
+
/** @hide */
- public long mNativeCanvas;
+ public long getNativeCanvas() {
+ return mNativeCanvas;
+ }
// may be null
private Bitmap mBitmap;
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index 69089b1..6ff5f4f 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -164,12 +164,12 @@
}
void drawSoftware(Canvas canvas, RectF location, Paint paint) {
- nativeDraw(canvas.mNativeCanvas, location, mBitmap.ni(), mNativeChunk,
+ nativeDraw(canvas.getNativeCanvas(), location, mBitmap.ni(), mNativeChunk,
paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity);
}
void drawSoftware(Canvas canvas, Rect location, Paint paint) {
- nativeDraw(canvas.mNativeCanvas, location, mBitmap.ni(), mNativeChunk,
+ nativeDraw(canvas.getNativeCanvas(), location, mBitmap.ni(), mNativeChunk,
paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity);
}
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 1e1128e..457b3ea 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -55,27 +55,6 @@
/**
* @hide
*/
- public boolean hasShadow;
- /**
- * @hide
- */
- public float shadowDx;
- /**
- * @hide
- */
- public float shadowDy;
- /**
- * @hide
- */
- public float shadowRadius;
- /**
- * @hide
- */
- public int shadowColor;
-
- /**
- * @hide
- */
public int mBidiFlags = BIDI_DEFAULT_LTR;
static final Style[] sStyleArray = {
@@ -492,12 +471,6 @@
mCompatScaling = 1;
mInvCompatScaling = 1;
- hasShadow = false;
- shadowDx = 0;
- shadowDy = 0;
- shadowRadius = 0;
- shadowColor = 0;
-
mBidiFlags = BIDI_DEFAULT_LTR;
setTextLocale(Locale.getDefault());
setElegantTextHeight(false);
@@ -538,12 +511,6 @@
mCompatScaling = paint.mCompatScaling;
mInvCompatScaling = paint.mInvCompatScaling;
- hasShadow = paint.hasShadow;
- shadowDx = paint.shadowDx;
- shadowDy = paint.shadowDy;
- shadowRadius = paint.shadowRadius;
- shadowColor = paint.shadowColor;
-
mBidiFlags = paint.mBidiFlags;
mLocale = paint.mLocale;
}
@@ -1135,22 +1102,24 @@
* layer is removed.
*/
public void setShadowLayer(float radius, float dx, float dy, int color) {
- hasShadow = radius > 0.0f;
- shadowRadius = radius;
- shadowDx = dx;
- shadowDy = dy;
- shadowColor = color;
- nSetShadowLayer(radius, dx, dy, color);
+ native_setShadowLayer(mNativePaint, radius, dx, dy, color);
}
-
- private native void nSetShadowLayer(float radius, float dx, float dy, int color);
/**
* Clear the shadow layer.
*/
public void clearShadowLayer() {
- hasShadow = false;
- nSetShadowLayer(0, 0, 0, 0);
+ setShadowLayer(0, 0, 0, 0);
+ }
+
+ /**
+ * Checks if the paint has a shadow layer attached
+ *
+ * @return true if the paint has a shadow layer attached and false otherwise
+ * @hide
+ */
+ public boolean hasShadowLayer() {
+ return native_hasShadowLayer(mNativePaint);
}
/**
@@ -2295,4 +2264,8 @@
private static native void nativeGetCharArrayBounds(long nativePaint,
char[] text, int index, int count, int bidiFlags, Rect bounds);
private static native void finalizer(long nativePaint);
+
+ private static native void native_setShadowLayer(long native_object,
+ float radius, float dx, float dy, int color);
+ private static native boolean native_hasShadowLayer(long native_object);
}
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
index 25188e0..a16c099 100644
--- a/graphics/java/android/graphics/Picture.java
+++ b/graphics/java/android/graphics/Picture.java
@@ -107,7 +107,7 @@
if (mRecordingCanvas != null) {
endRecording();
}
- nativeDraw(canvas.mNativeCanvas, mNativePicture);
+ nativeDraw(canvas.getNativeCanvas(), mNativePicture);
}
/**
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 61b1b85..99ab4dd 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -237,7 +237,7 @@
paint.setAlpha(modulateAlpha(prevAlpha, state.mAlpha));
// only draw shape if it may affect output
- if (paint.getAlpha() != 0 || paint.getXfermode() != null || paint.hasShadow) {
+ if (paint.getAlpha() != 0 || paint.getXfermode() != null || paint.hasShadowLayer()) {
final boolean clearColorFilter;
if (mTintFilter != null && paint.getColorFilter() == null) {
paint.setColorFilter(mTintFilter);
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 77712b6..ff4ab98 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -14,8 +14,6 @@
package android.graphics.drawable;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
@@ -31,9 +29,6 @@
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
import com.android.internal.R;
@@ -46,7 +41,6 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
-import java.util.HashSet;
/**
* This lets you create a drawable based on an XML vector graphic It can be
@@ -56,8 +50,6 @@
* <p/>
* <dl>
* <dt><code><vector></code></dt>
- * <dd>The attribute <code>android:trigger</code> defines a state change that
- * will drive the animation</dd>
* <dd>The attribute <code>android:versionCode</code> defines the version of
* VectorDrawable</dd>
* <dt><code><size></code></dt>
@@ -68,8 +60,7 @@
* The size is defined using the attributes <code>android:viewportHeight</code>
* <code>android:viewportWidth</code></dd>
* <dt><code><group></code></dt>
- * <dd>Defines a "key frame" in the animation if there is only one group the
- * drawable is static 2D image that has no animation.</dd>
+ * <dd>Defines the static 2D image.</dd>
* <dt><code><path></code></dt>
* <dd>Defines paths to be drawn. The path elements must be within a group
* <dl>
@@ -109,48 +100,6 @@
* <dd>Sets the lineJoin for a stroked path: miter,round,bevel</dd></dt>
* <dt><code>android:strokeMiterLimit</code>
* <dd>Sets the Miter limit for a stroked path</dd></dt>
- * <dt><code>android:state_pressed</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_focused</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_selected</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_window_focused</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_enabled</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_activated</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_accelerated</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_hovered</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_checked</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_checkable</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * </dl>
- * </dd>
- * <dt><code><animation></code></dt>
- * <dd>Used to customize the transition between two paths
- * <dl>
- * <dt><code>android:sequence</code>
- * <dd>Configures this animation sequence between the named paths.</dd></dt>
- * <dt><code>android:limitTo</code>
- * <dd>Limits an animation to only interpolate the selected variable unlimited,
- * path, rotation, trimPathStart, trimPathEnd, trimPathOffset</dd></dt>
- * <dt><code>android:repeatCount</code>
- * <dd>Number of times to loop this aspect of the animation</dd></dt>
- * <dt><code>android:durations</code>
- * <dd>The duration of each step in the animation in milliseconds Must contain
- * the number of named paths - 1</dd></dt>
- * <dt><code>android:startDelay</code>
- * <dd></dd></dt>
- * <dt><code>android:repeatStyle</code>
- * <dd>when repeating how does it repeat back and forth or a to b: forward,
- * inAndOut</dd></dt>
- * <dt><code>android:animate</code>
- * <dd>linear, accelerate, decelerate, easing</dd></dt>
* </dl>
* </dd>
*/
@@ -161,8 +110,6 @@
private static final String SHAPE_VIEWPORT = "viewport";
private static final String SHAPE_GROUP = "group";
private static final String SHAPE_PATH = "path";
- private static final String SHAPE_TRANSITION = "transition";
- private static final String SHAPE_ANIMATION = "animation";
private static final String SHAPE_VECTOR = "vector";
private static final int LINECAP_BUTT = 0;
@@ -173,9 +120,6 @@
private static final int LINEJOIN_ROUND = 1;
private static final int LINEJOIN_BEVEL = 2;
- private static final int DEFAULT_DURATION = 1000;
- private static final long DEFAULT_INFINITE_DURATION = 60 * 60 * 1000;
-
private final VectorDrawableState mVectorState;
private int mAlpha = 0xFF;
@@ -202,7 +146,7 @@
final int saveCount = canvas.save();
final Rect bounds = getBounds();
canvas.translate(bounds.left, bounds.top);
- mVectorState.mVAnimatedPath.draw(canvas, bounds.width(), bounds.height());
+ mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height());
canvas.restoreToCount(saveCount);
}
@@ -255,12 +199,12 @@
@Override
public int getIntrinsicWidth() {
- return (int) mVectorState.mVAnimatedPath.mBaseWidth;
+ return (int) mVectorState.mVPathRenderer.mBaseWidth;
}
@Override
public int getIntrinsicHeight() {
- return (int) mVectorState.mVAnimatedPath.mBaseHeight;
+ return (int) mVectorState.mVPathRenderer.mBaseHeight;
}
@Override
@@ -276,8 +220,8 @@
@Override
public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException {
- final VAnimatedPath p = inflateInternal(res, parser, attrs, theme);
- setAnimatedPath(p);
+ final VPathRenderer p = inflateInternal(res, parser, attrs, theme);
+ setPathRenderer(p);
}
@Override
@@ -290,7 +234,7 @@
super.applyTheme(t);
final VectorDrawableState state = mVectorState;
- final VAnimatedPath path = state.mVAnimatedPath;
+ final VPathRenderer path = state.mVPathRenderer;
if (path != null && path.canApplyTheme()) {
path.applyTheme(t);
}
@@ -316,9 +260,9 @@
return null;
}
- private VAnimatedPath inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
+ private VPathRenderer inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
Theme theme) throws XmlPullParserException, IOException {
- final VAnimatedPath animatedPath = new VAnimatedPath();
+ final VPathRenderer pathRenderer = new VPathRenderer();
boolean noSizeTag = true;
boolean noViewportTag = true;
@@ -336,23 +280,18 @@
path.inflate(res, attrs, theme);
currentGroup.add(path);
noPathTag = false;
- } else if (SHAPE_ANIMATION.equals(tagName)) {
- final VAnimation anim = new VAnimation();
- anim.inflate(animatedPath.mGroupList, res, attrs, theme);
- animatedPath.addAnimation(anim);
} else if (SHAPE_SIZE.equals(tagName)) {
- animatedPath.parseSize(res, attrs);
+ pathRenderer.parseSize(res, attrs);
noSizeTag = false;
} else if (SHAPE_VIEWPORT.equals(tagName)) {
- animatedPath.parseViewport(res, attrs);
+ pathRenderer.parseViewport(res, attrs);
noViewportTag = false;
} else if (SHAPE_GROUP.equals(tagName)) {
currentGroup = new VGroup();
- animatedPath.mGroupList.add(currentGroup);
+ pathRenderer.mGroupList.add(currentGroup);
noGroupTag = false;
} else if (SHAPE_VECTOR.equals(tagName)) {
final TypedArray a = res.obtainAttributes(attrs, R.styleable.VectorDrawable);
- animatedPath.setTrigger(a.getInteger(R.styleable.VectorDrawable_trigger, 0));
// Parsing the version information.
// Right now, we only support version "1".
@@ -403,23 +342,23 @@
}
// post parse cleanup
- animatedPath.parseFinish();
- return animatedPath;
+ pathRenderer.parseFinish();
+ return pathRenderer;
}
- private void setAnimatedPath(VAnimatedPath animatedPath) {
- mVectorState.mVAnimatedPath = animatedPath;
+ private void setPathRenderer(VPathRenderer pathRenderer) {
+ mVectorState.mVPathRenderer = pathRenderer;
}
private static class VectorDrawableState extends ConstantState {
int mChangingConfigurations;
- VAnimatedPath mVAnimatedPath;
+ VPathRenderer mVPathRenderer;
Rect mPadding;
public VectorDrawableState(VectorDrawableState copy) {
if (copy != null) {
mChangingConfigurations = copy.mChangingConfigurations;
- mVAnimatedPath = new VAnimatedPath(copy.mVAnimatedPath);
+ mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
mPadding = new Rect(copy.mPadding);
}
}
@@ -445,35 +384,16 @@
}
}
- private static class VAnimatedPath {
- private static final int [] TRIGGER_MAP = {
- 0,
- R.attr.state_pressed,
- R.attr.state_focused,
- R.attr.state_hovered,
- R.attr.state_selected,
- R.attr.state_checkable,
- R.attr.state_checked,
- R.attr.state_activated,
- R.attr.state_focused
- };
-
+ private static class VPathRenderer {
private final Path mPath = new Path();
private final Path mRenderPath = new Path();
private final Matrix mMatrix = new Matrix();
- private ArrayList<VAnimation> mCurrentAnimList;
private VPath[] mCurrentPaths;
private Paint mStrokePaint;
private Paint mFillPaint;
private PathMeasure mPathMeasure;
- private int[] mCurrentState = new int[0];
- private float mAnimationValue;
- private long mTotalDuration;
- private int mTrigger;
- private boolean mTriggerState;
-
final ArrayList<VGroup> mGroupList = new ArrayList<VGroup>();
float mBaseWidth = 1;
@@ -481,11 +401,10 @@
float mViewportWidth;
float mViewportHeight;
- public VAnimatedPath() {
+ public VPathRenderer() {
}
- public VAnimatedPath(VAnimatedPath copy) {
- mCurrentAnimList = new ArrayList<VAnimation>(copy.mCurrentAnimList);
+ public VPathRenderer(VPathRenderer copy) {
mGroupList.addAll(copy.mGroupList);
if (copy.mCurrentPaths != null) {
mCurrentPaths = new VPath[copy.mCurrentPaths.length];
@@ -493,15 +412,11 @@
mCurrentPaths[i] = new VPath(copy.mCurrentPaths[i]);
}
}
- mAnimationValue = copy.mAnimationValue; // time goes from 0 to 1
mBaseWidth = copy.mBaseWidth;
mBaseHeight = copy.mBaseHeight;
mViewportWidth = copy.mViewportHeight;
mViewportHeight = copy.mViewportHeight;
- mTotalDuration = copy.mTotalDuration;
- mTrigger = copy.mTrigger;
- mCurrentState = new int[0];
}
public boolean canApplyTheme() {
@@ -516,14 +431,6 @@
}
}
- final ArrayList<VAnimation> anims = mCurrentAnimList;
- for (int i = anims.size() - 1; i >= 0; i--) {
- final VAnimation anim = anims.get(i);
- if (anim.canApplyTheme()) {
- return true;
- }
- }
-
return false;
}
@@ -539,70 +446,6 @@
}
}
- final ArrayList<VAnimation> anims = mCurrentAnimList;
- for (int i = anims.size() - 1; i >= 0; i--) {
- final VAnimation anim = anims.get(i);
- if (anim.canApplyTheme()) {
- anim.applyTheme(t);
- }
- }
- }
-
- public void setTrigger(int trigger){
- mTrigger = VAnimatedPath.getStateForTrigger(trigger);
- }
-
- public long getTotalAnimationDuration() {
- mTotalDuration = 0;
- int size = mCurrentAnimList.size();
- for (int i = 0; i < size; i++) {
- VAnimation vAnimation = mCurrentAnimList.get(i);
- long t = vAnimation.getTotalDuration();
- if (t == -1) {
- mTotalDuration = -1;
- return -1;
- }
- mTotalDuration = Math.max(mTotalDuration, t);
- }
-
- return mTotalDuration;
- }
-
- public float getValue() {
- return mAnimationValue;
- }
-
- /**
- * @param value the point along the animations to show typically between 0.0f and 1.0f
- * @return true if you need to keep repeating
- */
- public boolean setAnimationFraction(float value) {
- getTotalAnimationDuration();
-
- long animationTime = (long) (value * mTotalDuration);
-
- final int len = mCurrentPaths.length;
- for (int i = 0; i < len; i++) {
- animationTime =
- (long) ((mTotalDuration == -1) ? value * 1000 : mTotalDuration * value);
-
- final VPath path = mCurrentPaths[i];
- final int size = mCurrentAnimList.size();
- for (int j = 0; j < size; j++) {
- final VAnimation vAnimation = mCurrentAnimList.get(j);
- if (vAnimation.doesAdjustPath(path)) {
- mCurrentPaths[i] = vAnimation.getPathAtTime(animationTime, path);
- }
- }
- }
-
- mAnimationValue = value;
-
- if (mTotalDuration == -1) {
- return true;
- } else {
- return animationTime < mTotalDuration;
- }
}
public void draw(Canvas canvas, int w, int h) {
@@ -612,7 +455,7 @@
}
for (int i = 0; i < mCurrentPaths.length; i++) {
- if (mCurrentPaths[i] != null && mCurrentPaths[i].isVisible(mCurrentState)) {
+ if (mCurrentPaths[i] != null) {
drawPath(mCurrentPaths[i], canvas, w, h);
}
}
@@ -694,34 +537,10 @@
}
/**
- * Ensure there is at least one animation for every path in group (linking them by names)
* Build the "current" path based on the first group
* TODO: improve memory use & performance or move to C++
*/
public void parseFinish() {
- final HashMap<String, VAnimation> newAnimations = new HashMap<String, VAnimation>();
- for (VGroup group : mGroupList) {
- for (VPath vPath : group.getPaths()) {
- if (!vPath.mAnimated) {
- VAnimation ap = null;
-
- if (!newAnimations.containsKey(vPath.getID())) {
- newAnimations.put(vPath.getID(), ap = new VAnimation());
- } else {
- ap = newAnimations.get(vPath.getID());
- }
-
- ap.addPath(vPath);
- vPath.mAnimated = true;
- }
- }
- }
-
- if (mCurrentAnimList == null) {
- mCurrentAnimList = new ArrayList<VectorDrawable.VAnimation>();
- }
- mCurrentAnimList.addAll(newAnimations.values());
-
final Collection<VPath> paths = mGroupList.get(0).getPaths();
mCurrentPaths = paths.toArray(new VPath[paths.size()]);
for (int i = 0; i < mCurrentPaths.length; i++) {
@@ -729,34 +548,6 @@
}
}
- public void setState(int[] state) {
- mCurrentState = Arrays.copyOf(state, state.length);
- }
-
- int getTrigger(int []state){
- if (mTrigger == 0) return 0;
- for (int i = 0; i < state.length; i++) {
- if (state[i] == mTrigger){
- if (mTriggerState)
- return 0;
- mTriggerState = true;
- return 1;
- }
- }
- if (mTriggerState) {
- mTriggerState = false;
- return -1;
- }
- return 0;
- }
-
- public void addAnimation(VAnimation anim) {
- if (mCurrentAnimList == null) {
- mCurrentAnimList = new ArrayList<VectorDrawable.VAnimation>();
- }
- mCurrentAnimList.add(anim);
- }
-
private void parseViewport(Resources r, AttributeSet attrs)
throws XmlPullParserException {
final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
@@ -781,329 +572,6 @@
a.recycle();
}
- private static final int getStateForTrigger(int trigger) {
- return TRIGGER_MAP[trigger];
- }
- }
-
- private static class VAnimation {
- private static final String SEPARATOR = ",";
-
- private static final int DIRECTION_FORWARD = 0;
- private static final int DIRECTION_IN_AND_OUT = 1;
-
- public enum Style {
- INTERPOLATE, CROSSFADE, WIPE
- }
-
- private final HashSet<String> mSeqMap = new HashSet<String>();
-
- private Interpolator mAnimInterpolator = new AccelerateDecelerateInterpolator();
- private VPath[] mPaths = new VPath[0];
- private long[] mDuration = { DEFAULT_DURATION };
-
- private int[] mThemeAttrs;
- private Style mStyle;
- private int mLimitProperty = 0;
- private long mStartOffset;
- private long mRepeat = 1;
- private long mWipeDirection;
- private int mMode = DIRECTION_FORWARD;
- private int mInterpolatorType;
- private String mId;
-
- public VAnimation() {
- // Empty constructor.
- }
-
- public void inflate(ArrayList<VGroup> groups, Resources r, AttributeSet attrs, Theme theme)
- throws XmlPullParserException {
- String value;
- String[] sp;
- int name;
-
- final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableAnimation);
- final int[] themeAttrs = a.extractThemeAttrs();
- mThemeAttrs = themeAttrs;
-
- value = a.getString(R.styleable.VectorDrawableAnimation_sequence);
- if (value != null) {
- sp = value.split(SEPARATOR);
- final VectorDrawable.VPath[] paths = new VectorDrawable.VPath[sp.length];
-
- for (int j = 0; j < sp.length; j++) {
- mSeqMap.add(sp[j].trim());
-
- final VectorDrawable.VPath path = groups.get(j).get(sp[j]);
- if (path == null) {
- throw new XmlPullParserException(a.getPositionDescription()
- + " missing path with name: " + sp[j]);
- }
-
- path.mAnimated = true;
- paths[j] = path;
- }
-
- setPaths(paths);
- }
-
- name = R.styleable.VectorDrawableAnimation_durations;
- value = a.getString(name);
- if (value != null) {
- long totalDuration = 0;
- sp = value.split(SEPARATOR);
-
- final long[] dur = new long[sp.length];
- for (int j = 0; j < dur.length; j++) {
- dur[j] = Long.parseLong(sp[j]);
- totalDuration += dur[j];
- }
-
- if (totalDuration == 0){
- throw new XmlPullParserException(a.getPositionDescription()
- + " total duration must not be zero");
- }
-
- setDuration(dur);
- }
-
- setLimitProperty(a.getInt(R.styleable.VectorDrawableAnimation_limitTo, 0));
- setRepeat(a.getInt(R.styleable.VectorDrawableAnimation_repeatCount, 1));
- setStartOffset(a.getInt(R.styleable.VectorDrawableAnimation_startDelay, 0));
- setMode(a.getInt(R.styleable.VectorDrawableAnimation_repeatStyle, 0));
-
- fixMissingParameters();
-
- a.recycle();
- }
-
- public boolean canApplyTheme() {
- return mThemeAttrs != null;
- }
-
- public void applyTheme(Theme t) {
- // TODO: Apply theme.
- }
-
- public boolean doesAdjustPath(VPath path) {
- return mSeqMap.contains(path.getID());
- }
-
- public String getId() {
- if (mId == null) {
- mId = mPaths[0].getID();
- for (int i = 1; i < mPaths.length; i++) {
- mId += mPaths[i].getID();
- }
- }
- return mId;
- }
-
- public String getPathName() {
- return mPaths[0].getID();
- }
-
- public Style getStyle() {
- return mStyle;
- }
-
- public void setStyle(Style style) {
- mStyle = style;
- }
-
- public int getLimitProperty() {
- return mLimitProperty;
- }
-
- public void setLimitProperty(int limitProperty) {
- mLimitProperty = limitProperty;
- }
-
- public long[] getDuration() {
- return mDuration;
- }
-
- public void setDuration(long[] duration) {
- mDuration = duration;
- }
-
- public long getRepeat() {
- return mRepeat;
- }
-
- public void setRepeat(long repeat) {
- mRepeat = repeat;
- }
-
- public long getStartOffset() {
- return mStartOffset;
- }
-
- public void setStartOffset(long startOffset) {
- mStartOffset = startOffset;
- }
-
- public long getWipeDirection() {
- return mWipeDirection;
- }
-
- public void setWipeDirection(long wipeDirection) {
- mWipeDirection = wipeDirection;
- }
-
- public int getMode() {
- return mMode;
- }
-
- public void setMode(int mode) {
- mMode = mode;
- }
-
- public int getInterpolator() {
- return mInterpolatorType;
- }
-
- public void setInterpolator(int interpolator) {
- mInterpolatorType = interpolator;
- }
-
- /**
- * compute the total time in milliseconds
- *
- * @return the total time in milliseconds the animation will take
- */
- public long getTotalDuration() {
- long total = mStartOffset;
- if (getRepeat() == -1) {
- return -1;
- }
- for (int i = 0; i < mDuration.length; i++) {
- if (mRepeat > 1) {
- total += mDuration[i] * mRepeat;
- } else {
- total += mDuration[i];
- }
- }
- return total;
- }
-
- public void setPaths(VPath[] paths) {
- mPaths = paths;
- }
-
- public void addPath(VPath path) {
- mPaths = Arrays.copyOf(mPaths, mPaths.length + 1);
- mPaths[mPaths.length - 1] = path;
- }
-
- public boolean containsPath(String pathid) {
- for (int i = 0; i < mPaths.length; i++) {
- if (mPaths[i].getID().equals(pathid)) {
- return true;
- }
- }
- return false;
- }
-
- public void interpolate(VPath p1, VPath p2, float time, VPath dest) {
- VPath.interpolate(time, p1, p2, dest, mLimitProperty);
- }
-
- public VPath getPathAtTime(long milliseconds, VPath dest) {
- if (mPaths.length == 1) {
- dest.copyFrom(mPaths[0]);
- return dest;
- }
- long point = milliseconds - mStartOffset;
- if (point < 0) {
- point = 0;
- }
- float time = 0;
- long sum = mDuration[0];
- for (int i = 1; i < mDuration.length; i++) {
- sum += mDuration[i];
- }
-
- if (mRepeat > 1) {
- time = point / (float) (sum * mRepeat);
- time = mAnimInterpolator.getInterpolation(time);
-
- if (mMode == DIRECTION_IN_AND_OUT) {
- point = ((long) (time * sum * 2 * mRepeat)) % (sum * 2);
- if (point > sum) {
- point = sum * 2 - point;
- }
- } else {
- point = ((long) (time * sum * mRepeat)) % sum;
- }
- } else if (mRepeat == 1) {
- time = point / (float) (sum * mRepeat);
- time = mAnimInterpolator.getInterpolation(time);
- if (mMode == DIRECTION_IN_AND_OUT) {
- point = ((long) (time * sum * 2 * mRepeat));
- if (point > sum) {
- point = sum * 2 - point;
- }
- } else {
- point = Math.min(((long) (time * sum * mRepeat)), sum);
- }
-
- } else { // repeat = -1
- if (mMode == DIRECTION_IN_AND_OUT) {
- point = point % (sum * 2);
- if (point > sum) {
- point = sum * 2 - point;
- }
- time = point / (float) sum;
- } else {
- point = point % sum;
- time = point / (float) sum;
- }
- }
-
- int transition = 0;
- while (point > mDuration[transition]) {
- point -= mDuration[transition++];
- }
- if (mPaths.length > (transition + 1)) {
- if (mPaths[transition].getID() != dest.getID()) {
- dest.copyFrom(mPaths[transition]);
- }
- interpolate(mPaths[transition], mPaths[transition + 1],
- point / (float) mDuration[transition], dest);
- } else {
- interpolate(mPaths[transition], mPaths[transition], 0, dest);
- }
- return dest;
- }
-
- void fixMissingParameters() {
- // fix missing points
- float rotation = Float.NaN;
- float rotationY = Float.NaN;
- float rotationX = Float.NaN;
- for (int i = 0; i < mPaths.length; i++) {
- if (mPaths[i].mPivotX > 0) {
- rotationX = mPaths[i].mPivotX;
- }
- if (mPaths[i].mPivotY > 0) {
- rotationY = mPaths[i].mPivotY;
- }
- if (mPaths[i].mRotate > 0) {
- rotation = mPaths[i].mRotate;
- }
- }
- if (rotation > 0) {
- for (int i = 0; i < mPaths.length; i++) {
- if (mPaths[i].mPivotX == 0) {
- mPaths[i].mPivotX = rotationX;
- }
- if (mPaths[i].mPivotY == 0) {
- mPaths[i].mPivotY = rotationY;
- }
- }
- }
- }
}
private static class VGroup {
@@ -1116,10 +584,6 @@
mVGList.add(path);
}
- public VPath get(String name) {
- return mVGPathMap.get(name);
- }
-
/**
* Must return in order of adding
* @return ordered list of paths
@@ -1128,23 +592,9 @@
return mVGList;
}
- public int size() {
- return mVGPathMap.size();
- }
}
private static class VPath {
- private static final int LIMIT_ALL = 0;
- private static final int LIMIT_PATH = 1;
- private static final int LIMIT_ROTATE = 2;
- private static final int LIMIT_TRIM_PATH_START = 3;
- private static final int LIMIT_TRIM_PATH_OFFSET = 5;
- private static final int LIMIT_TRIM_PATH_END = 4;
-
- private static final int STATE_UNDEFINED=0;
- private static final int STATE_TRUE=1;
- private static final int STATE_FALSE=2;
-
private static final int MAX_STATES = 10;
private int[] mThemeAttrs;
@@ -1165,7 +615,6 @@
float mTrimPathEnd = 1;
float mTrimPathOffset = 0;
- boolean mAnimated = false;
boolean mClip = false;
Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
Paint.Join mStrokeLineJoin = Paint.Join.MITER;
@@ -1176,7 +625,6 @@
private int[] mCheckState = new int[MAX_STATES];
private boolean[] mCheckValue = new boolean[MAX_STATES];
private int mNumberOfStates = 0;
- private int mNumberOfTrue = 0;
public VPath() {
// Empty constructor.
@@ -1186,38 +634,6 @@
copyFrom(p);
}
- public void addStateFilter(int state, boolean condition) {
- int k = 0;
- while (k < mNumberOfStates) {
- if (mCheckState[mNumberOfStates] == state)
- break;
- k++;
- }
- mCheckState[k] = state;
- mCheckValue[k] = condition;
- if (k==mNumberOfStates){
- mNumberOfStates++;
- }
- if (condition) {
- mNumberOfTrue++;
- }
- }
-
- private int getState(int state){
- for (int i = 0; i < mNumberOfStates; i++) {
- if (mCheckState[mNumberOfStates] == state){
- return (mCheckValue[i])?STATE_TRUE:STATE_FALSE;
- }
- }
- return STATE_UNDEFINED;
- }
- /**
- * @return the name of the path
- */
- public String getName() {
- return mId;
- }
-
public void toPath(Path path) {
path.reset();
if (mNode != null) {
@@ -1342,27 +758,6 @@
R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
}
- // TODO: Consider replacing this with existing state attributes.
- final int[] states = {
- R.styleable.VectorDrawablePath_state_activated,
- R.styleable.VectorDrawablePath_state_checkable,
- R.styleable.VectorDrawablePath_state_checked,
- R.styleable.VectorDrawablePath_state_enabled,
- R.styleable.VectorDrawablePath_state_focused,
- R.styleable.VectorDrawablePath_state_hovered,
- R.styleable.VectorDrawablePath_state_pressed,
- R.styleable.VectorDrawablePath_state_selected,
- R.styleable.VectorDrawablePath_state_window_focused
- };
-
- final int N = states.length;
- for (int i = 0; i < N; i++) {
- final int state = states[i];
- if (a.hasValue(state)) {
- addStateFilter(state, a.getBoolean(state, false));
- }
- }
-
updateColorAlphas();
a.recycle();
@@ -1530,7 +925,6 @@
mRotate = p1.mRotate;
mPivotX = p1.mPivotX;
mPivotY = p1.mPivotY;
- mAnimated = p1.mAnimated;
mTrimPathStart = p1.mTrimPathStart;
mTrimPathEnd = p1.mTrimPathEnd;
mTrimPathOffset = p1.mTrimPathOffset;
@@ -1545,118 +939,6 @@
mFillRule = p1.mFillRule;
}
-
- public static VPath interpolate(float t, VPath p1, VPath p2, VPath returnPath, int limit) {
- if (limit == LIMIT_ALL || limit == LIMIT_PATH) {
- if (returnPath.mNode == null || returnPath.mNode.length != p1.mNode.length) {
- returnPath.mNode = new VNode[p1.mNode.length];
- }
- for (int i = 0; i < returnPath.mNode.length; i++) {
- if (returnPath.mNode[i] == null) {
- returnPath.mNode[i] = new VNode(p1.mNode[i], p2.mNode[i], t);
- } else {
- returnPath.mNode[i].interpolate(p1.mNode[i], p2.mNode[i], t);
- }
- }
- }
- float t1 = 1 - t;
- switch (limit) {
- case LIMIT_ALL:
- returnPath.mRotate = t1 * p1.mRotate + t * p2.mRotate;
- returnPath.mPivotX = t1 * p1.mPivotX + t * p2.mPivotX;
- returnPath.mPivotY = t1 * p1.mPivotY + t * p2.mPivotY;
- returnPath.mClip = p1.mClip | p2.mClip;
-
- returnPath.mTrimPathStart = t1 * p1.mTrimPathStart + t * p2.mTrimPathStart;
- returnPath.mTrimPathEnd = t1 * p1.mTrimPathEnd + t * p2.mTrimPathEnd;
- returnPath.mTrimPathOffset = t1 * p1.mTrimPathOffset + t * p2.mTrimPathOffset;
- returnPath.mStrokeMiterlimit =
- t1 * p1.mStrokeMiterlimit + t * p2.mStrokeMiterlimit;
- returnPath.mStrokeLineCap = p1.mStrokeLineCap;
- if (returnPath.mStrokeLineCap == null) {
- returnPath.mStrokeLineCap = p2.mStrokeLineCap;
- }
- returnPath.mStrokeLineJoin = p1.mStrokeLineJoin;
- if (returnPath.mStrokeLineJoin == null) {
- returnPath.mStrokeLineJoin = p2.mStrokeLineJoin;
- }
- returnPath.mFillRule = p1.mFillRule;
-
- returnPath.mStrokeColor = rgbInterpolate(t, p1.mStrokeColor, p2.mStrokeColor);
- returnPath.mFillColor = rgbInterpolate(t, p1.mFillColor, p2.mFillColor);
- returnPath.mStrokeWidth = t1 * p1.mStrokeWidth + t * p2.mStrokeWidth;
- returnPath.mNumberOfStates = p1.mNumberOfStates;
- for (int i = 0; i < returnPath.mNumberOfStates; i++) {
- returnPath.mCheckState[i] = p1.mCheckState[i];
- returnPath.mCheckValue[i] = p1.mCheckValue[i];
- }
- for (int i = 0; i < p2.mNumberOfStates; i++) {
- returnPath.addStateFilter(p2.mCheckState[i], p2.mCheckValue[i]);
- }
-
- int count = 0;
- for (int i = 0; i < returnPath.mNumberOfStates; i++) {
- if (returnPath.mCheckValue[i]) {
- count++;
- }
- }
- returnPath.mNumberOfTrue = count;
- break;
- case LIMIT_ROTATE:
- returnPath.mRotate = t1 * p1.mRotate + t * p2.mRotate;
- break;
- case LIMIT_TRIM_PATH_END:
- returnPath.mTrimPathEnd = t1 * p1.mTrimPathEnd + t * p2.mTrimPathEnd;
- break;
- case LIMIT_TRIM_PATH_OFFSET:
- returnPath.mTrimPathOffset = t1 * p1.mTrimPathOffset + t * p2.mTrimPathOffset;
- break;
- case LIMIT_TRIM_PATH_START:
- returnPath.mTrimPathStart = t1 * p1.mTrimPathStart + t * p2.mTrimPathStart;
- break;
- }
- return returnPath;
- }
-
- private static int rgbInterpolate(float fraction, int startColor, int endColor) {
- if (startColor == endColor) {
- return startColor;
- } else if (startColor == 0) {
- return endColor;
- } else if (endColor == 0) {
- return startColor;
- }
-
- final int startA = (startColor >> 24) & 0xff;
- final int startR = (startColor >> 16) & 0xff;
- final int startG = (startColor >> 8) & 0xff;
- final int startB = startColor & 0xff;
-
- final int endA = (endColor >> 24) & 0xff;
- final int endR = (endColor >> 16) & 0xff;
- final int endG = (endColor >> 8) & 0xff;
- final int endB = endColor & 0xff;
-
- return ((startA + (int)(fraction * (endA - startA))) << 24) |
- ((startR + (int)(fraction * (endR - startR))) << 16) |
- ((startG + (int)(fraction * (endG - startG))) << 8) |
- ((startB + (int)(fraction * (endB - startB))));
- }
-
- public boolean isVisible(int[] state) {
- int match = 0;
- for (int i = 0; i < state.length; i++) {
- int v = getState(state[i]);
- if (v != STATE_UNDEFINED) {
- if (v==STATE_TRUE) {
- match++;
- } else {
- return false;
- }
- }
- }
- return match == mNumberOfTrue;
- }
}
private static class VNode {
@@ -1673,25 +955,6 @@
mParams = Arrays.copyOf(n.mParams, n.mParams.length);
}
- public VNode(VNode n1, VNode n2, float t) {
- mType = n1.mType;
- mParams = new float[n1.mParams.length];
- interpolate(n1, n2, t);
- }
-
- private boolean match(VNode n) {
- if (n.mType != mType) {
- return false;
- }
- return (mParams.length == n.mParams.length);
- }
-
- public void interpolate(VNode n1, VNode n2, float t) {
- for (int i = 0; i < n1.mParams.length; i++) {
- mParams[i] = n1.mParams[i] * (1 - t) + n2.mParams[i] * t;
- }
- }
-
public static void createPath(VNode[] node, Path path) {
float[] current = new float[4];
char previousCommand = 'm';
@@ -1747,7 +1010,6 @@
break;
}
for (int k = 0; k < val.length; k += incr) {
- // TODO: build test to prove all permutations work
switch (cmd) {
case 'm': // moveto - Start a new sub-path (relative)
path.rMoveTo(val[k + 0], val[k + 1]);
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 3d58964..45b6624 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -190,7 +190,7 @@
// Overlapping other operations is only allowed for text without shadow. For other ops,
// multiDraw isn't guaranteed to overdraw correctly
- if (!isTextBatch || state->mDrawModifiers.mHasShadow) {
+ if (!isTextBatch || op->hasTextShadow()) {
if (intersects(state->mBounds)) return false;
}
const DeferredDisplayState* lhs = state;
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index ce92beb..f1d70eb 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -183,6 +183,10 @@
return OpenGLRenderer::getAlphaDirect(mPaint);
}
+ virtual bool hasTextShadow() const {
+ return false;
+ }
+
inline float strokeWidthOutset() {
// since anything AA stroke with less than 1.0 pixel width is drawn with an alpha-reduced
// 1.0 stroke, treat 1.0 as minimum.
@@ -244,11 +248,11 @@
bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
localBounds.set(mLocalBounds);
- if (drawModifiers.mHasShadow) {
- // TODO: inspect paint's looper directly
+ OpenGLRenderer::TextShadow textShadow;
+ if (OpenGLRenderer::getTextShadow(mPaint, &textShadow)) {
Rect shadow(mLocalBounds);
- shadow.translate(drawModifiers.mShadowDx, drawModifiers.mShadowDy);
- shadow.outset(drawModifiers.mShadowRadius);
+ shadow.translate(textShadow.dx, textShadow.dx);
+ shadow.outset(textShadow.radius);
localBounds.unionWith(shadow);
}
return true;
@@ -619,41 +623,6 @@
SkiaShader* mShader;
};
-class ResetShadowOp : public StateOp {
-public:
- virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
- renderer.resetShadow();
- }
-
- virtual void output(int level, uint32_t logFlags) const {
- OP_LOGS("ResetShadow");
- }
-
- virtual const char* name() { return "ResetShadow"; }
-};
-
-class SetupShadowOp : public StateOp {
-public:
- SetupShadowOp(float radius, float dx, float dy, int color)
- : mRadius(radius), mDx(dx), mDy(dy), mColor(color) {}
-
- virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
- renderer.setupShadow(mRadius, mDx, mDy, mColor);
- }
-
- virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("SetupShadow, radius %f, %f, %f, color %#x", mRadius, mDx, mDy, mColor);
- }
-
- virtual const char* name() { return "SetupShadow"; }
-
-private:
- float mRadius;
- float mDx;
- float mDy;
- int mColor;
-};
-
class ResetPaintFilterOp : public StateOp {
public:
virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
@@ -1351,6 +1320,10 @@
OP_LOG("Draw some text, %d bytes", mBytesCount);
}
+ virtual bool hasTextShadow() const {
+ return OpenGLRenderer::hasTextShadow(mPaint);
+ }
+
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
const DeferredDisplayState& state) {
const SkPaint* paint = getPaint(renderer);
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 8afd106..c2ce6ed 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -410,16 +410,6 @@
addStateOp(new (alloc()) SetupShaderOp(shader));
}
-void DisplayListRenderer::resetShadow() {
- addStateOp(new (alloc()) ResetShadowOp());
- OpenGLRenderer::resetShadow();
-}
-
-void DisplayListRenderer::setupShadow(float radius, float dx, float dy, int color) {
- addStateOp(new (alloc()) SetupShadowOp(radius, dx, dy, color));
- OpenGLRenderer::setupShadow(radius, dx, dy, color);
-}
-
void DisplayListRenderer::resetPaintFilter() {
addStateOp(new (alloc()) ResetPaintFilterOp());
}
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 25e78c1..185179a 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -102,9 +102,6 @@
virtual void resetShader();
virtual void setupShader(SkiaShader* shader);
- virtual void resetShadow();
- virtual void setupShadow(float radius, float dx, float dy, int color);
-
virtual void resetPaintFilter();
virtual void setupPaintFilter(int clearBits, int setBits);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 95fdb04..87b07b3 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -379,49 +379,9 @@
dirtyClip();
}
-void OpenGLRenderer::detachFunctor(Functor* functor) {
- mFunctors.remove(functor);
-}
-
-void OpenGLRenderer::attachFunctor(Functor* functor) {
- mFunctors.add(functor);
-}
-
-status_t OpenGLRenderer::invokeFunctors(Rect& dirty) {
- status_t result = DrawGlInfo::kStatusDone;
- size_t count = mFunctors.size();
-
- if (count > 0) {
- interrupt();
- SortedVector<Functor*> functors(mFunctors);
- mFunctors.clear();
-
- DrawGlInfo info;
- info.clipLeft = 0;
- info.clipTop = 0;
- info.clipRight = 0;
- info.clipBottom = 0;
- info.isLayer = false;
- info.width = 0;
- info.height = 0;
- memset(info.transform, 0, sizeof(float) * 16);
-
- for (size_t i = 0; i < count; i++) {
- Functor* f = functors.itemAt(i);
- result |= (*f)(DrawGlInfo::kModeProcess, &info);
- }
- resume();
- }
-
- return result;
-}
-
status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
- detachFunctor(functor);
-
-
Rect clip(*currentClipRect());
clip.snapToPixelBoundaries();
@@ -2694,28 +2654,32 @@
FontRenderer& fontRenderer, int alpha, float x, float y) {
mCaches.activeTexture(0);
+ TextShadow textShadow;
+ if (!getTextShadow(paint, &textShadow)) {
+ LOG_ALWAYS_FATAL("failed to query shadow attributes");
+ }
+
// NOTE: The drop shadow will not perform gamma correction
// if shader-based correction is enabled
mCaches.dropShadowCache.setFontRenderer(fontRenderer);
const ShadowTexture* shadow = mCaches.dropShadowCache.get(
- paint, text, bytesCount, count, mDrawModifiers.mShadowRadius, positions);
+ paint, text, bytesCount, count, textShadow.radius, positions);
// If the drop shadow exceeds the max texture size or couldn't be
// allocated, skip drawing
if (!shadow) return;
const AutoTexture autoCleanup(shadow);
- const float sx = x - shadow->left + mDrawModifiers.mShadowDx;
- const float sy = y - shadow->top + mDrawModifiers.mShadowDy;
+ const float sx = x - shadow->left + textShadow.dx;
+ const float sy = y - shadow->top + textShadow.dy;
- const int shadowAlpha = ((mDrawModifiers.mShadowColor >> 24) & 0xFF) * mSnapshot->alpha;
- int shadowColor = mDrawModifiers.mShadowColor;
+ const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * mSnapshot->alpha;
if (mDrawModifiers.mShader) {
- shadowColor = 0xffffffff;
+ textShadow.color = SK_ColorWHITE;
}
setupDraw();
setupDrawWithTexture(true);
- setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha);
+ setupDrawAlpha8Color(textShadow.color, shadowAlpha < 255 ? shadowAlpha : alpha);
setupDrawColorFilter(getColorFilter(paint));
setupDrawShader();
setupDrawBlending(paint, true);
@@ -2732,7 +2696,7 @@
}
bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
- float alpha = (mDrawModifiers.mHasShadow ? 1.0f : paint->getAlpha()) * mSnapshot->alpha;
+ float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * mSnapshot->alpha;
return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
}
@@ -2764,7 +2728,7 @@
SkXfermode::Mode mode;
getAlphaAndMode(paint, &alpha, &mode);
- if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
+ if (CC_UNLIKELY(hasTextShadow(paint))) {
drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
alpha, 0.0f, 0.0f);
}
@@ -2841,7 +2805,7 @@
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
- if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
+ if (CC_UNLIKELY(hasTextShadow(paint))) {
fontRenderer.setFont(paint, mat4::identity());
drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
alpha, oldX, oldY);
@@ -3062,22 +3026,6 @@
}
///////////////////////////////////////////////////////////////////////////////
-// Drop shadow
-///////////////////////////////////////////////////////////////////////////////
-
-void OpenGLRenderer::resetShadow() {
- mDrawModifiers.mHasShadow = false;
-}
-
-void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) {
- mDrawModifiers.mHasShadow = true;
- mDrawModifiers.mShadowRadius = radius;
- mDrawModifiers.mShadowDx = dx;
- mDrawModifiers.mShadowDy = dy;
- mDrawModifiers.mShadowColor = color;
-}
-
-///////////////////////////////////////////////////////////////////////////////
// Draw filters
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 7794abc..1d46945 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -29,6 +29,7 @@
#include <SkShader.h>
#include <SkXfermode.h>
+#include <utils/Blur.h>
#include <utils/Functor.h>
#include <utils/RefBase.h>
#include <utils/SortedVector.h>
@@ -72,13 +73,6 @@
SkiaShader* mShader;
float mOverrideLayerAlpha;
- // Drop shadow
- bool mHasShadow;
- float mShadowRadius;
- float mShadowDx;
- float mShadowDy;
- int mShadowColor;
-
// Draw filters
bool mHasDrawFilter;
int mPaintFilterClearBits;
@@ -151,9 +145,6 @@
return mCountOverdraw ? mOverdraw : 0.0f;
}
- ANDROID_API status_t invokeFunctors(Rect& dirty);
- ANDROID_API void detachFunctor(Functor* functor);
- ANDROID_API void attachFunctor(Functor* functor);
virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty);
ANDROID_API void pushLayerUpdate(Layer* layer);
@@ -229,9 +220,6 @@
virtual void resetShader();
virtual void setupShader(SkiaShader* shader);
- virtual void resetShadow();
- virtual void setupShadow(float radius, float dx, float dy, int color);
-
virtual void resetPaintFilter();
virtual void setupPaintFilter(int clearBits, int setBits);
@@ -319,6 +307,31 @@
return paint->getAlpha();
}
+ struct TextShadow {
+ SkScalar radius;
+ float dx;
+ float dy;
+ SkColor color;
+ };
+
+ static inline bool getTextShadow(const SkPaint* paint, TextShadow* textShadow) {
+ SkDrawLooper::BlurShadowRec blur;
+ if (paint && paint->getLooper() && paint->getLooper()->asABlurShadow(&blur)) {
+ if (textShadow) {
+ textShadow->radius = Blur::convertSigmaToRadius(blur.fSigma);
+ textShadow->dx = blur.fOffset.fX;
+ textShadow->dy = blur.fOffset.fY;
+ textShadow->color = blur.fColor;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ static inline bool hasTextShadow(const SkPaint* paint) {
+ return getTextShadow(paint, NULL);
+ }
+
/**
* Return the best transform to use to rasterize text given a full
* transform matrix.
@@ -959,8 +972,6 @@
// List of rectangles to clear after saveLayer() is invoked
Vector<Rect*> mLayers;
- // List of functors to invoke after a frame is drawn
- SortedVector<Functor*> mFunctors;
// List of layers to update at the beginning of a frame
Vector<Layer*> mLayerUpdates;
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index 3209a53..57db816 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -178,9 +178,6 @@
virtual void resetShader() = 0;
virtual void setupShader(SkiaShader* shader) = 0;
- virtual void resetShadow() = 0;
- virtual void setupShadow(float radius, float dx, float dy, int color) = 0;
-
virtual void resetPaintFilter() = 0;
virtual void setupPaintFilter(int clearBits, int setBits) = 0;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index fc3548c..5a23158 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -349,6 +349,8 @@
mDirtyRegionsEnabled = mGlobalContext->enableDirtyRegions(mEglSurface);
mHaveNewSurface = true;
makeCurrent();
+ } else {
+ mRenderThread.removeFrameCallback(this);
}
}
@@ -385,6 +387,10 @@
mCanvas->setViewport(width, height);
}
+void CanvasContext::setOpaque(bool opaque) {
+ mOpaque = opaque;
+}
+
void CanvasContext::makeCurrent() {
// TODO: Figure out why this workaround is needed, see b/13913604
// In the meantime this matches the behavior of GLRenderer, so it is not a regression
@@ -468,6 +474,10 @@
// Called by choreographer to do an RT-driven animation
void CanvasContext::doFrame() {
+ if (CC_UNLIKELY(!mCanvas || mEglSurface == EGL_NO_SURFACE)) {
+ return;
+ }
+
ATRACE_CALL();
TreeInfo info;
@@ -486,10 +496,7 @@
requireGlContext();
mode = DrawGlInfo::kModeProcess;
}
- // TODO: Remove the dummy info in the future
- DrawGlInfo dummyInfo;
- memset(&dummyInfo, 0, sizeof(DrawGlInfo));
- (*functor)(mode, &dummyInfo);
+ (*functor)(mode, NULL);
if (mCanvas) {
mCanvas->resume();
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index a95e27a..dcb9858 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -52,6 +52,7 @@
void updateSurface(EGLNativeWindowType window);
void pauseSurface(EGLNativeWindowType window);
void setup(int width, int height);
+ void setOpaque(bool opaque);
void makeCurrent();
void prepareDraw(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
void draw(Rect* dirty);
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index c2806fa..82a2dbc 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -159,6 +159,18 @@
post(task);
}
+CREATE_BRIDGE2(setOpaque, CanvasContext* context, bool opaque) {
+ args->context->setOpaque(args->opaque);
+ return NULL;
+}
+
+void RenderProxy::setOpaque(bool opaque) {
+ SETUP_TASK(setOpaque);
+ args->context = mContext;
+ args->opaque = opaque;
+ post(task);
+}
+
int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos,
int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) {
mDrawFrameTask.setDirty(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 013c3bd..4a7e70a 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -67,6 +67,7 @@
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 setOpaque(bool opaque);
ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos,
int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
ANDROID_API void destroyCanvasAndSurface();
diff --git a/libs/hwui/utils/Blur.cpp b/libs/hwui/utils/Blur.cpp
index 85d90d0..c020b40 100644
--- a/libs/hwui/utils/Blur.cpp
+++ b/libs/hwui/utils/Blur.cpp
@@ -23,6 +23,31 @@
namespace android {
namespace uirenderer {
+// This constant approximates the scaling done in the software path's
+// "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)).
+static const float BLUR_SIGMA_SCALE = 0.57735f;
+
+float Blur::convertRadiusToSigma(float radius) {
+ return radius > 0 ? BLUR_SIGMA_SCALE * radius + 0.5f : 0.0f;
+}
+
+float Blur::convertSigmaToRadius(float sigma) {
+ return sigma > 0.5f ? (sigma - 0.5f) / BLUR_SIGMA_SCALE : 0.0f;
+}
+
+/**
+ * HWUI has used a slightly different equation than Skia to generate the value
+ * for sigma and to preserve compatibility we have kept that logic.
+ *
+ * Based on some experimental radius and sigma values we approximate the
+ * equation sigma = f(radius) as sigma = radius * 0.3 + 0.6. The larger the
+ * radius gets, the more our gaussian blur will resemble a box blur since with
+ * large sigma the gaussian curve begins to lose its shape.
+ */
+static float legacyConvertRadiusToSigma(float radius) {
+ return radius > 0 ? 0.3f * radius + 0.6f : 0.0f;
+}
+
void Blur::generateGaussianWeights(float* weights, int32_t radius) {
// Compute gaussian weights for the blur
// e is the euler's number
@@ -31,13 +56,7 @@
// g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
// x is of the form [-radius .. 0 .. radius]
// and sigma varies with radius.
- // Based on some experimental radius values and sigma's
- // we approximately fit sigma = f(radius) as
- // sigma = radius * 0.3 + 0.6
- // The larger the radius gets, the more our gaussian blur
- // will resemble a box blur since with large sigma
- // the gaussian curve begins to lose its shape
- float sigma = 0.3f * (float) radius + 0.6f;
+ float sigma = legacyConvertRadiusToSigma((float) radius);
// Now compute the coefficints
// We will store some redundant values to save some math during
diff --git a/libs/hwui/utils/Blur.h b/libs/hwui/utils/Blur.h
index 6c176e9..79aff65 100644
--- a/libs/hwui/utils/Blur.h
+++ b/libs/hwui/utils/Blur.h
@@ -18,12 +18,18 @@
#define ANDROID_HWUI_BLUR_H
#include <stdint.h>
+#include <cutils/compiler.h>
namespace android {
namespace uirenderer {
class Blur {
public:
+ // If radius > 0, return the corresponding sigma, else return 0
+ ANDROID_API static float convertRadiusToSigma(float radius);
+ // If sigma > 0.6, return the corresponding radius, else return 0
+ ANDROID_API static float convertSigmaToRadius(float sigma);
+
static void generateGaussianWeights(float* weights, int32_t radius);
static void horizontal(float* weights, int32_t radius, const uint8_t* source,
uint8_t* dest, int32_t width, int32_t height);
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 1899685..007eb40 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -172,16 +172,14 @@
public @interface WriteMode {}
/**
- * @hide CANDIDATE FOR PUBLIC API
* The write mode indicating the write operation will block until all data has been written,
- * to be used in {@link #write(ByteBuffer, int, int, int)}.
+ * to be used in {@link #write(ByteBuffer, int, int)}
*/
public final static int WRITE_BLOCKING = 0;
/**
- * @hide CANDIDATE FOR PUBLIC API
* The write mode indicating the write operation will return immediately after
* queuing as much audio data for playback as possible without blocking, to be used in
- * {@link #write(ByteBuffer, int, int, int)}.
+ * {@link #write(ByteBuffer, int, int)}.
*/
public final static int WRITE_NON_BLOCKING = 1;
@@ -1220,7 +1218,6 @@
/**
- * @hide CANDIDATE FOR PUBLIC API
* Writes the audio data to the audio sink for playback (streaming mode),
* or copies audio data for later playback (static buffer mode).
* In static buffer mode, copies the data to the buffer starting at its 0 offset, and the write
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index ca77f04..3ff07d9 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -31,8 +31,8 @@
interface ISession {
void sendEvent(String event, in Bundle data);
ISessionController getController();
- void setTransportPerformerEnabled();
- void publish();
+ void setFlags(int flags);
+ void setActive(boolean active);
void destroy();
// These commands are for setting up and communicating with routes
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 84b9a0f..7a8c22e 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -15,6 +15,7 @@
package android.media.session;
+import android.content.ComponentName;
import android.media.session.ISession;
import android.media.session.ISessionCallback;
import android.os.Bundle;
@@ -25,4 +26,5 @@
*/
interface ISessionManager {
ISession createSession(String packageName, in ISessionCallback cb, String tag);
+ List<IBinder> getSessions(in ComponentName compName);
}
\ No newline at end of file
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index 4ee67d1..c07229d 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -43,7 +43,8 @@
private Handler mHandler = new Handler(Looper.getMainLooper());
// The legacy APIs use PendingIntents to register/unregister media button
// receivers and these are associated with RCC.
- private ArrayMap<PendingIntent, SessionHolder> mSessions = new ArrayMap<PendingIntent, SessionHolder>();
+ private ArrayMap<PendingIntent, SessionHolder> mSessions
+ = new ArrayMap<PendingIntent, SessionHolder>();
private MediaSessionLegacyHelper(Context context) {
mSessionManager = (SessionManager) context
@@ -78,6 +79,8 @@
}
performer.addListener(listener, mHandler);
holder.mRccListener = listener;
+ holder.mFlags |= Session.FLAG_HANDLES_TRANSPORT_CONTROLS;
+ holder.mSession.setFlags(holder.mFlags);
holder.update();
}
@@ -86,6 +89,8 @@
if (holder != null && holder.mRccListener != null) {
holder.mSession.getTransportPerformer().removeListener(holder.mRccListener);
holder.mRccListener = null;
+ holder.mFlags &= ~Session.FLAG_HANDLES_TRANSPORT_CONTROLS;
+ holder.mSession.setFlags(holder.mFlags);
holder.update();
}
}
@@ -98,6 +103,8 @@
return;
}
holder.mMediaButtonListener = new MediaButtonListener(pi, context);
+ holder.mFlags |= Session.FLAG_HANDLES_MEDIA_BUTTONS;
+ holder.mSession.setFlags(holder.mFlags);
holder.mSession.getTransportPerformer().addListener(holder.mMediaButtonListener, mHandler);
}
@@ -105,6 +112,9 @@
SessionHolder holder = getHolder(pi, false);
if (holder != null && holder.mMediaButtonListener != null) {
holder.mSession.getTransportPerformer().removeListener(holder.mMediaButtonListener);
+ holder.mFlags &= ~Session.FLAG_HANDLES_MEDIA_BUTTONS;
+ holder.mSession.setFlags(holder.mFlags);
+ holder.mMediaButtonListener = null;
holder.update();
}
}
@@ -113,8 +123,7 @@
SessionHolder holder = mSessions.get(pi);
if (holder == null && createIfMissing) {
Session session = mSessionManager.createSession(TAG);
- session.setTransportPerformerEnabled();
- session.publish();
+ session.setActive(true);
holder = new SessionHolder(session, pi);
mSessions.put(pi, holder);
}
@@ -193,6 +202,7 @@
public final PendingIntent mPi;
public MediaButtonListener mMediaButtonListener;
public TransportPerformer.Listener mRccListener;
+ public int mFlags;
public SessionHolder(Session session, PendingIntent pi) {
mSession = session;
diff --git a/media/java/android/media/session/Session.java b/media/java/android/media/session/Session.java
index 8ccd788..194679e7 100644
--- a/media/java/android/media/session/Session.java
+++ b/media/java/android/media/session/Session.java
@@ -45,12 +45,13 @@
* media to multiple routes or to provide finer grain controls of media.
* <p>
* A MediaSession is created by calling
- * {@link SessionManager#createSession(String)}. Once a session is created
- * apps that have the MEDIA_CONTENT_CONTROL permission can interact with the
- * session through {@link SessionManager#getActiveSessions()}. The owner of
- * the session may also use {@link #getSessionToken()} to allow apps without
- * this permission to create a {@link SessionController} to interact with this
- * session.
+ * {@link SessionManager#createSession(String)}. Once a session is created apps
+ * that have the MEDIA_CONTENT_CONTROL permission can interact with the session
+ * through
+ * {@link SessionManager#getActiveSessions(android.content.ComponentName)}. The
+ * owner of the session may also use {@link #getSessionToken()} to allow apps
+ * without this permission to create a {@link SessionController} to interact
+ * with this session.
* <p>
* To receive commands, media keys, and other events a Callback must be set with
* {@link #addCallback(Callback)}.
@@ -63,6 +64,28 @@
public final class Session {
private static final String TAG = "Session";
+ /**
+ * Set this flag on the session to indicate that it can handle media button
+ * events.
+ */
+ public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1 << 0;
+
+ /**
+ * Set this flag on the session to indicate that it handles commands through
+ * the {@link TransportPerformer}. The performer can be retrieved by calling
+ * {@link #getTransportPerformer()}.
+ */
+ public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
+
+ /**
+ * System only flag for a session that needs to have priority over all other
+ * sessions. This flag ensures this session will receive media button events
+ * regardless of the current ordering in the system.
+ *
+ * @hide
+ */
+ public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 1 << 16;
+
private static final int MSG_MEDIA_BUTTON = 1;
private static final int MSG_COMMAND = 2;
private static final int MSG_ROUTE_CHANGE = 3;
@@ -86,7 +109,7 @@
private TransportPerformer mPerformer;
private Route mRoute;
- private boolean mPublished = false;;
+ private boolean mActive = false;;
/**
* @hide
@@ -101,6 +124,7 @@
throw new RuntimeException("Dead object in MediaSessionController constructor: ", e);
}
mSessionToken = new SessionToken(controllerBinder);
+ mPerformer = new TransportPerformer(mBinder);
}
/**
@@ -148,56 +172,57 @@
}
/**
- * Start using a TransportPerformer with this media session. This must be
- * called before calling publish and cannot be called more than once.
- * Calling this will allow MediaControllers to retrieve a
- * TransportController.
+ * Retrieves the {@link TransportPerformer} for this session. To receive
+ * commands through the performer you must also set the
+ * {@link #FLAG_HANDLES_TRANSPORT_CONTROLS} flag using
+ * {@link #setFlags(int)}.
*
- * @see TransportController
- * @return The TransportPerformer created for this session
- */
- public TransportPerformer setTransportPerformerEnabled() {
- if (mPerformer != null) {
- throw new IllegalStateException("setTransportPerformer can only be called once.");
- }
- if (mPublished) {
- throw new IllegalStateException("setTransportPerformer cannot be called after publish");
- }
-
- mPerformer = new TransportPerformer(mBinder);
- try {
- mBinder.setTransportPerformerEnabled();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Failure in setTransportPerformerEnabled.", e);
- }
- return mPerformer;
- }
-
- /**
- * Retrieves the TransportPerformer used by this session. If called before
- * {@link #setTransportPerformerEnabled} null will be returned.
- *
- * @return The TransportPerformer associated with this session or null
+ * @return The performer associated with this session.
*/
public TransportPerformer getTransportPerformer() {
return mPerformer;
}
/**
- * Call after you have finished setting up the session. This will make it
- * available to listeners and begin pushing updates to MediaControllers.
- * This can only be called once.
+ * Set any flags for the session.
+ *
+ * @param flags The flags to set for this session.
*/
- public void publish() {
- if (mPublished) {
- throw new RuntimeException("publish() may only be called once.");
+ public void setFlags(int flags) {
+ try {
+ mBinder.setFlags(flags);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Failure in setFlags.", e);
+ }
+ }
+
+ /**
+ * Set if this session is currently active and ready to receive commands. If
+ * set to false your session's controller may not be discoverable. You must
+ * set the session to active before it can start receiving media button
+ * events or transport commands.
+ *
+ * @param active Whether this session is active or not.
+ */
+ public void setActive(boolean active) {
+ if (mActive == active) {
+ return;
}
try {
- mBinder.publish();
+ mBinder.setActive(active);
+ mActive = active;
} catch (RemoteException e) {
- Log.wtf(TAG, "Failure in publish.", e);
+ Log.wtf(TAG, "Failure in setActive.", e);
}
- mPublished = true;
+ }
+
+ /**
+ * Get the current active state of this session.
+ *
+ * @return True if the session is active, false otherwise.
+ */
+ public boolean isActive() {
+ return mActive;
}
/**
diff --git a/media/java/android/media/session/SessionManager.java b/media/java/android/media/session/SessionManager.java
index 15bf0e3..fd022fc 100644
--- a/media/java/android/media/session/SessionManager.java
+++ b/media/java/android/media/session/SessionManager.java
@@ -16,11 +16,13 @@
package android.media.session;
+import android.content.ComponentName;
import android.content.Context;
import android.media.session.ISessionManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.service.notification.NotificationListenerService;
import android.util.Log;
import java.util.ArrayList;
@@ -79,12 +81,27 @@
/**
* Get a list of controllers for all ongoing sessions. This requires the
* android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by
- * the calling app.
+ * the calling app. You may also retrieve this list if your app is an
+ * enabled notification listener using the
+ * {@link NotificationListenerService} APIs, in which case you must pass the
+ * {@link ComponentName} of your enabled listener.
*
- * @return a list of controllers for ongoing sessions
+ * @param notificationListener The enabled notification listener component.
+ * May be null.
+ * @return A list of controllers for ongoing sessions
*/
- public List<SessionController> getActiveSessions() {
- // TODO
- return new ArrayList<SessionController>();
+ public List<SessionController> getActiveSessions(ComponentName notificationListener) {
+ ArrayList<SessionController> controllers = new ArrayList<SessionController>();
+ try {
+ List<IBinder> binders = mService.getSessions(notificationListener);
+ for (int i = binders.size() - 1; i >= 0; i--) {
+ SessionController controller = SessionController.fromBinder(ISessionController.Stub
+ .asInterface(binders.get(i)));
+ controllers.add(controller);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get active sessions: ", e);
+ }
+ return controllers;
}
}
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index ed98b96..90fe695 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -66,8 +66,6 @@
LOCAL_CFLAGS +=
-LOCAL_LDLIBS := -lpthread
-
LOCAL_MODULE:= libmedia_jni
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index abebd48..6f42057 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -648,7 +648,7 @@
return;
}
- clazz = env->FindClass("android/net/ProxyProperties");
+ clazz = env->FindClass("android/net/ProxyInfo");
if (clazz == NULL) {
return;
}
@@ -660,7 +660,7 @@
env->GetMethodID(clazz, "getPort", "()I");
fields.proxyConfigGetExclusionList =
- env->GetMethodID(clazz, "getExclusionList", "()Ljava/lang/String;");
+ env->GetMethodID(clazz, "getExclusionListAsString", "()Ljava/lang/String;");
}
static void
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-hdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..c779437
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-mdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..98ba690
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-xhdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..61947ea
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-xxhdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..0b563b1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..3600ee6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/layout-sw600dp/heads_up.xml b/packages/SystemUI/res/layout-sw600dp/heads_up.xml
index 71f7c21..f7035fe 100644
--- a/packages/SystemUI/res/layout-sw600dp/heads_up.xml
+++ b/packages/SystemUI/res/layout-sw600dp/heads_up.xml
@@ -25,7 +25,6 @@
android:id="@+id/content_holder"
android:layout_height="wrap_content"
android:layout_width="@dimen/notification_panel_width"
- android:layout_marginStart="@dimen/notification_panel_margin_left"
android:background="@drawable/heads_up_window_bg"
/>
</com.android.systemui.statusbar.policy.HeadsUpNotificationView>
diff --git a/packages/SystemUI/res/layout/flip_settings.xml b/packages/SystemUI/res/layout/flip_settings.xml
index f3c1b90..28d9625 100644
--- a/packages/SystemUI/res/layout/flip_settings.xml
+++ b/packages/SystemUI/res/layout/flip_settings.xml
@@ -22,5 +22,4 @@
android:layout_height="wrap_content"
android:background="#5f000000"
android:animateLayoutChanges="true"
- android:visibility="gone"
android:columnCount="@integer/quick_settings_num_columns" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/heads_up.xml b/packages/SystemUI/res/layout/heads_up.xml
index 3a58b84..e4954e7 100644
--- a/packages/SystemUI/res/layout/heads_up.xml
+++ b/packages/SystemUI/res/layout/heads_up.xml
@@ -22,6 +22,5 @@
android:layout_height="wrap_content"
android:layout_width="@dimen/notification_panel_width"
android:id="@+id/content_holder"
- android:layout_marginStart="@dimen/notification_panel_margin_left"
android:background="@drawable/notification_panel_bg"
/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index ec5acba..194829d 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -55,4 +55,14 @@
android:textStyle="italic"
android:textAppearance="?android:attr/textAppearanceMedium"/>
+ <ImageView
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_gravity="bottom|center_horizontal"
+ android:src="@drawable/ic_lock_24dp"
+ android:scaleType="center"
+ android:alpha="0.7"
+ android:layerType="hardware"
+ android:tint="#ffffffff"/>
+
</com.android.systemui.statusbar.phone.KeyguardBottomAreaView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 761ad42..3267c36 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -23,9 +23,7 @@
xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
android:id="@+id/notification_panel"
android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:paddingTop="@dimen/notification_panel_padding_top"
- android:layout_marginStart="@dimen/notification_panel_margin_left"
+ android:layout_height="match_parent"
>
<include
@@ -36,15 +34,6 @@
android:layout_gravity="bottom"
/>
- <include
- layout="@layout/status_bar_flip_button"
- android:id="@+id/keyguard_flipper"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:layout_gravity="right|top"
- android:layout_marginTop="@dimen/status_bar_height"
- android:visibility="gone" />
-
<com.android.keyguard.CarrierText
android:id="@+id/keyguard_carrier_text"
android:layout_width="wrap_content"
@@ -54,11 +43,6 @@
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceMedium" />
- <include layout="@layout/status_bar_expanded_header"
- android:layout_width="match_parent"
- android:layout_height="@dimen/notification_panel_header_height"
- />
-
<include
layout="@layout/keyguard_status_view"
android:layout_height="wrap_content"
@@ -74,27 +58,54 @@
android:visibility="gone"
/>
- <FrameLayout
+ <com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
android:id="@+id/notification_container_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/close_handle_underlap"
- >
- <include
- layout="@layout/flip_settings"
- android:layout_marginTop="@dimen/notification_panel_header_height"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+
+ <com.android.systemui.statusbar.phone.ObservableScrollView
+ android:id="@+id/scroll_view"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- />
+ android:layout_height="match_parent"
+ android:visibility="invisible"
+ android:scrollbars="none"
+ android:fillViewport="true">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <include
+ layout="@layout/flip_settings"
+ android:layout_marginTop="@dimen/status_bar_header_height_expanded"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <!-- A view to reserve space for the collapsed stack -->
+ <View
+ android:layout_height="@dimen/collapsed_stack_height"
+ android:layout_width="match_parent"/>
+ </LinearLayout>
+ </com.android.systemui.statusbar.phone.ObservableScrollView>
+
<com.android.systemui.statusbar.stack.NotificationStackScrollLayout
android:id="@+id/notification_stack_scroller"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- />
- </FrameLayout>
+ android:layout_height="match_parent"
+ android:layout_marginBottom="@dimen/close_handle_underlap"/>
+
+ </com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer>
+
+
+ <include layout="@layout/status_bar_expanded_header"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/status_bar_header_height"
+ />
<include
layout="@layout/keyguard_bottom_area"
android:visibility="gone" />
+
</com.android.systemui.statusbar.phone.NotificationPanelView><!-- end of sliding panel -->
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 8975728..460dd4b 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -15,21 +15,30 @@
** limitations under the License.
-->
-<LinearLayout
+<!-- Extends RelativeLayout -->
+<com.android.systemui.statusbar.phone.StatusBarHeaderView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
android:id="@+id/header"
android:layout_width="match_parent"
- android:layout_height="@dimen/notification_panel_header_height"
- android:background="@drawable/notification_header_bg"
+ android:layout_height="@dimen/status_bar_header_height"
android:orientation="horizontal"
android:gravity="center_vertical"
android:baselineAligned="false"
>
+
+ <View
+ android:id="@+id/background"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/notification_header_bg"
+ android:clickable="true"
+ />
<RelativeLayout
android:id="@+id/datetime"
android:layout_width="wrap_content"
android:layout_height="match_parent"
+ android:layout_gravity="start"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:background="@drawable/ic_notify_button_bg"
@@ -55,12 +64,6 @@
/>
</RelativeLayout>
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"
- />
-
<TextView
android:id="@+id/header_debug_info"
android:visibility="invisible"
@@ -74,18 +77,22 @@
android:padding="2dp"
/>
+ <include layout="@layout/status_bar_flip_button"
+ android:id="@+id/header_flipper"
+ android:layout_width="50dp"
+ android:layout_height="50dp"
+ android:layout_alignParentEnd="true"/>
+
<ImageView android:id="@+id/clear_all_button"
android:layout_width="50dp"
android:layout_height="50dp"
+ android:layout_toStartOf="@id/header_flipper"
android:scaleType="center"
android:src="@drawable/ic_notify_clear"
android:background="@drawable/ic_notify_button_bg"
android:contentDescription="@string/accessibility_clear_all"
/>
- <include layout="@layout/status_bar_flip_button"
- android:id="@+id/header_flipper"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:layout_marginStart="12dp" />
-</LinearLayout>
+
+
+</com.android.systemui.statusbar.phone.StatusBarHeaderView>
diff --git a/packages/SystemUI/res/layout/status_bar_flip_button.xml b/packages/SystemUI/res/layout/status_bar_flip_button.xml
index b7dff8c..f4d7033 100644
--- a/packages/SystemUI/res/layout/status_bar_flip_button.xml
+++ b/packages/SystemUI/res/layout/status_bar_flip_button.xml
@@ -15,22 +15,11 @@
~ limitations under the License
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="50dp"
- android:layout_height="50dp">
- <ImageView android:id="@+id/settings_button"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:scaleType="center"
- android:src="@drawable/ic_notify_settings"
- android:background="@drawable/ic_notify_button_bg"
- android:contentDescription="@string/accessibility_desc_quick_settings" />
- <ImageView android:id="@+id/notification_button"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:scaleType="center"
- android:src="@drawable/ic_notifications"
- android:background="@drawable/ic_notify_button_bg"
- android:visibility="gone"
- android:contentDescription="@string/accessibility_notifications_button" />
-</FrameLayout>
\ No newline at end of file
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/settings_button"
+ android:layout_width="50dp"
+ android:layout_height="50dp"
+ android:scaleType="center"
+ android:src="@drawable/ic_notify_quicksettings"
+ android:background="@drawable/ic_notify_button_bg"
+ android:contentDescription="@string/accessibility_desc_quick_settings"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
index 2e08bff..30eedee 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
@@ -18,7 +18,7 @@
<com.android.systemui.statusbar.NotificationOverflowContainer
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="32dp"
+ android:layout_height="40dp"
android:focusable="true"
android:clickable="true"
>
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 61d43d7..f9b022c 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -33,11 +33,10 @@
<com.android.systemui.statusbar.phone.PanelHolder
android:id="@+id/panel_holder"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginTop="@dimen/panel_holder_padding_top">
+ android:layout_height="match_parent" >
<include layout="@layout/status_bar_expanded"
android:layout_width="@dimen/notification_panel_width"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_gravity="start|top" />
</com.android.systemui.statusbar.phone.PanelHolder>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index d8a3114..8ec48c8 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Onlangse programme"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Deursoek"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knoppie vir wissel van invoermetode."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Versoenbaarheid-zoem se knoppie."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoem kleiner na groter skerm."</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 9d1e036..7aaaaf3 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"የቅርብ ጊዜ መተግበሪያዎች"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"ፈልግ"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"ካሜራ"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"የግቤት ስልት አዝራር ቀይር"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"የተኳኋኝአጉላ አዝራር።"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"አነስተኛውን ማያ ወደ ትልቅ አጉላ።"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 22a032a..1c06615 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"التطبيقات الحديثة"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"بحث"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"الكاميرا"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"الهاتف"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"زر تبديل طريقة الإدخال."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"زر تكبير/تصغير للتوافق."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"استخدام التكبير/التصغير لتحويل شاشة صغيرة إلى شاشة أكبر"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 00ac707..febcab6 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Скорошни приложения"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Търсене"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Бутон за превключване на метода на въвеждане."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Бутон за промяна на мащаба с цел съвместимост."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Промяна на мащаба на екрана от по-малък до по-голям."</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index bfad5bc..658ece0 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Aplicacions recents"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Cerca"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Càmera"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botó de canvi del mètode d\'entrada."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botó de zoom de compatibilitat."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Amplia menys com més gran sigui la pantalla."</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 94ba5c7..c7d2703 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Nové aplikace"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Hledat"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparát"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačítko přepnutí metody zadávání"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tlačítko úpravy velikosti z důvodu kompatibility"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zvětšit menší obrázek na větší obrazovku."</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index df442ab..c740051 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Seneste apps"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Søg"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Skift indtastningsmetode-knappen."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knap for kompatibilitetszoom."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom mindre til større skærm."</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 451476c..40ecc49 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Kürzlich geöffnete Apps"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Suchen"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefonnummer"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Schaltfläche zum Ändern der Eingabemethode"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Schaltfläche für Kompatibilitätszoom"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom auf einen größeren Bildschirm"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 6dcffcf..0e98ce0 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Πρόσφατες εφαρμογές"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Αναζήτηση"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Φωτογραφική μηχανή"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Τηλέφωνο"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Κουμπί εναλλαγής μεθόδου εισόδου"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Κουμπί εστίασης συμβατότητας."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Ζουμ από μικρότερη σε μεγαλύτερη οθόνη."</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 91a334a..f4098b7 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Recent apps"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Search"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Camera"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Phone"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 91a334a..f4098b7 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Recent apps"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Search"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Camera"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Phone"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 2150cbe..51198e6 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Aplicaciones recientes"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Buscar"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Cámara"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidad"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de pantalla más pequeña a más grande"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 3424166..1b73e18 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Aplicaciones recientes"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Buscar"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Cámara"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Teléfono"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidad"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de pantalla más pequeña a más grande"</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 8dbf9af..0f95c60 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Hiljutised rakendused"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Otsing"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kaamera"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Sisestusmeetodi vahetamise nupp."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Sobivussuumi nupp."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Suumi suuremale ekraanile vähem."</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index b2ac990..f36d04b 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"برنامههای اخیر"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"جستجو"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"دوربین"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"کلید تغییر روش ورود متن."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"دکمه بزرگنمایی سازگار."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"بزرگنمایی از صفحههای کوچک تا بزرگ."</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index af0df4d..4ae3851 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Viimeaikaiset sovellukset"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Haku"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Syöttötavan vaihtopainike."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Yhteensopivuuszoomaus-painike."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoomaa pienemmältä suuremmalle ruudulle."</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index f01c99a..c55a5fc 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Applications récentes"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Rechercher"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Appareil photo"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Bouton \"Zoom de compatibilité\""</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilité avec la taille de l\'écran"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 5efbd2f..1121918 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Applications récentes"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Rechercher"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Appareil photo"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Bouton \"Zoom de compatibilité\""</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilité avec la taille de l\'écran"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index e6d38ef..f9e6aad 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"हाल ही के ऐप्स"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"खोजें"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"कैमरा"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"फ़ोन"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धति बटन स्विच करें."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"संगतता ज़ूम बटन."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"छोटी से बड़ी स्क्रीन पर ज़ूम करें."</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index b777b8f..435f701 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Nedavne aplikacije"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Pretraži"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparat"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Gumb za promjenu načina unosa."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Gumb za kompatibilnost zumiranja."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zumiranje manjeg zaslona na veći."</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 10732fe..7685477 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Legújabb alkalmazás"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Keresés"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Beviteli mód váltása gomb."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kompatibilitási zoom gomb."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kicsinyítsen a nagyobb képernyőhöz."</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index f1c4869..7a8ab10 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Վերջին ծրագրերը"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Որոնել"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Ֆոտոխցիկ"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Միացնել մուտքագրման եղանակի կոճակը:"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Համատեղելիության խոշորացման կոճակը:"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Դիտափոխել փոքրից ավելի մեծ էկրան:"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index f0b0713..cdb0816 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Apl terbaru"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Telusuri"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telepon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tombol beralih metode masukan."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tombol perbesar/perkecil kompatibilitas."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Perbesar dari layar kecil ke besar."</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 6a57682..401dbce 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Applicazioni recenti"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Cerca"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Fotocamera"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefono"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Pulsante per cambiare metodo di immissione."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Pulsante zoom compatibilità."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom inferiore per schermo più grande."</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 3e87b76..08ffc54 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"אפליקציות אחרונות"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"חפש"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"מצלמה"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"לחצן החלפת שיטת קלט."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"לחצן מרחק מתצוגה של תאימות."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"שנה מרחק מתצוגה של מסך קטן לגדול יותר."</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 1edb630..2caa069 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"最近使ったアプリ"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"検索"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"カメラ"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"入力方法の切り替えボタン。"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"互換ズームボタン。"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"小さい画面から大きい画面に拡大。"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 9d4344a..62e40d0 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"ბოლოს გამოყენებული აპები"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"ძიება"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"კამერა"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"შეყვანის მეთოდის გადართვის ღილაკი."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"თავსებადი მასშტაბირების ღილაკი."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"შეცვალეთ პატარა ეკრანი უფრო დიდით."</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index bb2d3b9..35a6917 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"កម្មវិធីថ្មីៗ"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"ស្វែងរក"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"ម៉ាស៊ីនថត"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ប្ដូរប៊ូតុងវិធីសាស្ត្របញ្ចូល។"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ប៊ូតុងពង្រីកត្រូវគ្នា។"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ពង្រីក/បង្រួមអេក្រង់ពីទៅធំ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 83ffa9f..d7cd13b 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"최근에 사용한 앱"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"검색"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"카메라"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"입력 방법 버튼을 전환합니다."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"호환성 확대/축소 버튼입니다."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"작은 화면을 큰 화면으로 확대합니다."</string>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 9a3d483..991fb66 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"ແອັບຯຫຼ້າສຸດ"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"ຊອກຫາ"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"ກ້ອງ"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"ໂທລະສັບ"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ປຸ່ມສະລັບຮູບແບບການປ້ອນຂໍ້ມູນ."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ປຸ່ມຊູມທີ່ໃຊ້ຮ່ວມກັນໄດ້."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ຊູມຈໍນ້ອຍໄປເປັນຈໍຂະຫນາດໃຫຍ່."</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 379cfce..87087b4 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Naujausios programos"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Ieškoti"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparatas"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefonas"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Perjungti įvesties metodo mygtuką."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Suderinamumo priartinimo mygtukas."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Padidinti ekraną."</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index ca07095..04571e7 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Nesen izmantotās lietotnes"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Meklēt"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Tālruņa numurs"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Ievades metodes maiņas poga."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Saderības tālummaiņas poga."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Veikt tālummaiņu no mazāka ekrāna uz lielāku."</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 4545301..3e7b660 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Сүүлийн апп"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Хайх"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Камер"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Оруулах аргыг сэлгэх товч."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Тохиромжтой өсгөх товч."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Жижгээс том дэлгэцрүү өсгөх."</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 587b84f..af50786 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Aplikasi terbaharu"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Cari"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Butang tukar kaedah input."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Butang zum keserasian."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Skrin zum lebih kecil kepada lebih besar."</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 001e733..9fa68b9 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Nylige apper"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Søk"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefonnummer"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bytt knapp for inndatametode."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Zoomknapp for kompatibilitet."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom fra mindre til større skjerm."</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 8a6e33b..8cf16bf 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Recente apps"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Zoeken"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Camera"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefoon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knop voor wijzigen invoermethode."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knop voor compatibiliteitszoom."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kleiner scherm uitzoomen naar groter scherm."</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 4862d1b..e51341d 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Ostatnie aplikacje"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Szukaj"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Aparat"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Przycisk przełączania metody wprowadzania."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Przycisk powiększenia na potrzeby zgodności."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Powiększa mniejszy ekran do większego."</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 012283a..11843b6 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Aplicações recentes"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Pesquisar"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Câmara"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telemóvel"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alternar botão de método de introdução."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão zoom de compatibilidade."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom menor para ecrã maior."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 0978d18..162d763 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Aplicativos recentes"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Pesquisar"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Câmera"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alterar botão do método de entrada."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão de zoom da compatibilidade."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Aumentar a tela com zoom."</string>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index 25f643f..9f82651 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -126,6 +126,8 @@
<skip />
<!-- no translation found for accessibility_camera_button (8064671582820358152) -->
<skip />
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<!-- no translation found for accessibility_ime_switch_button (5032926134740456424) -->
<skip />
<!-- no translation found for accessibility_compatibility_zoom_button (8461115318742350699) -->
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 5c9764a..75ba35b 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Aplicaţii recente"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Căutați"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Cameră foto"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Buton pentru comutarea metodei de introducere."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Buton zoom pentru compatibilitate."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Faceţi zoom de la o imagine mai mică la una mai mare."</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 976a793..6bdc6f4 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Недавние приложения"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Поиск"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка переключения способа ввода."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабирования (режим совместимости)"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Уменьшение изображения для увеличения свободного места на экране."</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 1224c3a..12c90ec 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Nové aplikácie"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Hľadať"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparát"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačidlo prepnutia metódy vstupu."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tlačidlo úpravy veľkosti z dôvodu kompatibility."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zväčšiť menší obrázok na väčšiu obrazovku."</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 10011bc..48d7727 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Nedavni programi"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Iskanje"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparat"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Gumb za preklop načina vnosa."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Gumb povečave za združljivost."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Povečava manjšega na večji zaslon."</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 0c6a939..dba27a1 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Недавне апликације"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Претражите"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Телефон"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Дугме Промени метод уноса."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Дугме Зум компатибилности."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Зумирање са мањег на већи екран."</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index d8bd1b1..0d58ed3 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Senaste apparna"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Sök"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Mobil"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knapp för byte av inmatningsmetod."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knapp för kompatibilitetszoom."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zooma mindre skärm till större."</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index d308b518..b626f78 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -76,6 +76,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Programu za hivi karibuni"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Tafuta"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Swichi kitufe cha mbinu ingizi."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kichupo cha kukuza kwa utangamanifu"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kuza kidogo kwa skrini kubwa."</string>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
deleted file mode 100644
index c6c0719..0000000
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2012, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
--->
-<resources>
- <!-- Layout parameters for the notification panel -->
- <dimen name="notification_panel_margin_bottom">0dp</dimen>
- <dimen name="notification_panel_margin_left">32dp</dimen>
-</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 92e3885..7372181 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -19,10 +19,6 @@
<!-- The width of the notification panel window: 446 + 16 + 16 (padding in the bg drawable) -->
<dimen name="notification_panel_width">478dp</dimen>
- <!-- Layout parameters for the notification panel -->
- <dimen name="notification_panel_margin_bottom">192dp</dimen>
- <dimen name="notification_panel_margin_left">16dp</dimen>
-
<!-- Gravity for the notification panel -->
<!-- 0x31 = top|center_horizontal -->
<integer name="notification_panel_layout_gravity">0x31</integer>
@@ -43,9 +39,6 @@
<dimen name="status_bar_recents_thumbnail_width">200dp</dimen>
<dimen name="status_bar_recents_thumbnail_height">177dp</dimen>
- <!-- On tablets, panels drop from the statusbar instead of overlapping it. -->
- <dimen name="panel_holder_padding_top">@*android:dimen/status_bar_height</dimen>
-
<!-- Minimum fraction of the screen that should be taken up by the notification panel. -->
<item type="dimen" name="notification_panel_min_height_frac">40%</item>
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index b1fc00a..a1c5b66 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -24,8 +24,6 @@
<!-- The width of the ticker, including the icon -->
<dimen name="notification_ticker_width">360dp</dimen>
- <!-- Status bar panel bottom offset (height of status bar - overlap) -->
- <dimen name="status_bar_panel_bottom_offset">36dp</dimen>
<!-- gap on either side of status bar notification icons -->
<dimen name="status_bar_icon_padding">1dp</dimen>
<!-- The width of the notification panel window -->
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 7929a30..6cb4a48 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"แอปพลิเคชันล่าสุด"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"ค้นหา"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"กล้องถ่ายรูป"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ปุ่มสลับวิธีการป้อนข้อมูล"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ปุ่มซูมที่ใช้งานร่วมกันได้"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ซูมหน้าจอให้มีขนาดใหญ่ขึ้น"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 92473a4..17e720e 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Kamakailang apps"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Hanapin"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Camera"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Ilipat ang button na pamamaraan ng pag-input."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Button ng zoom ng pagiging tugma."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Mag-zoom nang mas maliit sa mas malaking screen."</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 9837ff8..1bf033f5 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Son uygulamalar"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Ara"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Giriş yöntemini değiştirme düğmesi."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Uyumluluk zum düğmesi."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Daha büyük ekrana daha küçük yakınlaştır."</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 534f520..a5284ae 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Останні програми"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Пошук"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Номер телефону"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка перемикання методу введення."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабування сумісності."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Збільшення екрана."</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 56fc89c..8df2449 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Ứng dụng gần đây"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Tìm kiếm"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Máy ảnh"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Nút chuyển phương thức nhập."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Nút thu phóng khả năng tương thích."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Thu phóng màn hình lớn hơn hoặc nhỏ hơn."</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 442fdb7..8643ca8 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"最近运行的应用"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"搜索"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"相机"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"输入法切换按钮。"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"兼容性缩放按钮。"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"将小屏幕的图片放大在较大屏幕上显示。"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 54a3b1e..9d93094 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"最近使用的應用程式"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"搜尋"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"相機"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"電話"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index fc74f53..07b7841 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -78,6 +78,8 @@
<string name="accessibility_recent" msgid="8571350598987952883">"最近使用的應用程式"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"搜尋"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"相機"</string>
+ <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+ <skip />
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index dfe8838..48a1ace 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -78,6 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Izinhlelo zokusebenza zakamuva"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Sesha"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Ikhamela"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Ifoni"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Vula indlela yokungena yenkinobho"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Inkinobho evumelekile yokusondeza"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Sondeza kancane esikrinini esikhudlwana"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c3ccb59..c0376f0 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -99,9 +99,6 @@
<integer name="blinds_pop_duration_ms">10</integer>
- <!-- The device supports quick settings. -->
- <bool name="config_hasQuickSettings">true</bool>
-
<!-- Should "4G" be shown instead of "LTE" when the network is NETWORK_TYPE_LTE? -->
<bool name="config_show4GForLTE">true</bool>
@@ -121,6 +118,8 @@
<integer name="recents_animate_task_bar_exit_duration">150</integer>
<!-- The animation duration for animating in the info pane. -->
<integer name="recents_animate_task_view_info_pane_duration">150</integer>
+ <!-- The animation duration for animating the removal of a task view. -->
+ <integer name="recents_animate_task_view_remove_duration">150</integer>
<!-- The minimum alpha for the dim applied to cards that go deeper into the stack. -->
<integer name="recents_max_task_stack_view_dim">96</integer>
<!-- Transposes the search bar layout in landscape -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index d763bd6..c6fdc16 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -152,21 +152,11 @@
<!-- Amount of close_handle that will NOT overlap the notification list -->
<dimen name="close_handle_underlap">32dp</dimen>
- <!-- Height of the notification panel header bar -->
- <dimen name="notification_panel_header_height">48dp</dimen>
+ <!-- Height of the status bar header bar -->
+ <dimen name="status_bar_header_height">48dp</dimen>
- <!-- Extra space above the panel -->
- <dimen name="notification_panel_padding_top">0dp</dimen>
-
- <!-- Extra space above the clock in the panel -->
- <dimen name="notification_panel_header_padding_top">0dp</dimen>
-
- <!-- Extra space above the panel holder -->
- <dimen name="panel_holder_padding_top">0dp</dimen>
-
- <!-- Layout parameters for the notification panel -->
- <dimen name="notification_panel_margin_bottom">0dp</dimen>
- <dimen name="notification_panel_margin_left">0dp</dimen>
+ <!-- Height of the status bar header bar when expanded -->
+ <dimen name="status_bar_header_height_expanded">144dp</dimen>
<!-- Gravity for the notification panel -->
<!-- 0x37 = fill_horizontal|top -->
@@ -233,6 +223,9 @@
<!-- The translation in the Z index for each task above the last task. -->
<dimen name="recents_task_view_z_increment">5dp</dimen>
+ <!-- The amount to translate when animating the removal of a task. -->
+ <dimen name="recents_task_view_remove_anim_translation_x">75dp</dimen>
+
<!-- The amount of space a user has to scroll to dismiss any info panes. -->
<dimen name="recents_task_stack_scroll_dismiss_info_pane_distance">50dp</dimen>
@@ -261,6 +254,9 @@
<!-- The padding between the individual notification cards. -->
<dimen name="notification_padding">3dp</dimen>
+ <!-- The total height of the stack in its collapsed size (i.e. when quick settings is open) -->
+ <dimen name="collapsed_stack_height">94dp</dimen>
+
<!-- Width of the zen mode interstitial dialog. -->
<dimen name="zen_mode_dialog_width">320dp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
new file mode 100644
index 0000000..6418930
--- /dev/null
+++ b/packages/SystemUI/res/values/ids.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
+ -->
+
+<resources>
+ <item type="id" name="translation_y_animator_tag"/>
+ <item type="id" name="translation_z_animator_tag"/>
+ <item type="id" name="scale_animator_tag"/>
+ <item type="id" name="alpha_animator_tag"/>
+ <item type="id" name="top_inset_animator_tag"/>
+ <item type="id" name="height_animator_tag"/>
+ <item type="id" name="translation_y_animator_end_value_tag"/>
+ <item type="id" name="translation_z_animator_end_value_tag"/>
+ <item type="id" name="scale_animator_end_value_tag"/>
+ <item type="id" name="alpha_animator_end_value_tag"/>
+ <item type="id" name="top_inset_animator_end_value_tag"/>
+ <item type="id" name="height_animator_end_value_tag"/>
+ <item type="id" name="translation_y_animator_start_value_tag"/>
+ <item type="id" name="translation_z_animator_start_value_tag"/>
+ <item type="id" name="scale_animator_start_value_tag"/>
+ <item type="id" name="alpha_animator_start_value_tag"/>
+ <item type="id" name="top_inset_animator_start_value_tag"/>
+ <item type="id" name="height_animator_start_value_tag"/>
+</resources>
+
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index d38d828..6387a92 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -322,6 +322,7 @@
anim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animator) {
updateAlphaFromOffset(animView, canAnimViewBeDismissed);
+ mCallback.onChildSnappedBack(animView);
}
});
anim.start();
@@ -407,5 +408,7 @@
void onChildDismissed(View v);
void onDragCancelled(View v);
+
+ void onChildSnappedBack(View animView);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 35c824b..0759b8e 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -217,6 +217,10 @@
public void onDragCancelled(View v) {
}
+ @Override
+ public void onChildSnappedBack(View animView) {
+ }
+
public View getChildAtPosition(MotionEvent ev) {
final float x = ev.getX() + getScrollX();
final float y = ev.getY() + getScrollY();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 297fe0d..c2dde6a 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -225,6 +225,10 @@
public void onDragCancelled(View v) {
}
+ @Override
+ public void onChildSnappedBack(View animView) {
+ }
+
public View getChildAtPosition(MotionEvent ev) {
final float x = ev.getX() + getScrollX();
final float y = ev.getY() + getScrollY();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 396cb14..3ef8316 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -64,7 +64,7 @@
mSingleCountFirstTaskRect.offset(0, (int) statusBarHeight);
mMultipleCountFirstTaskRect = replyData.getParcelable(KEY_MULTIPLE_TASK_STACK_RECT);
mMultipleCountFirstTaskRect.offset(0, (int) statusBarHeight);
- Console.log(Constants.DebugFlags.App.RecentsComponent,
+ Console.log(Constants.Log.App.RecentsComponent,
"[RecentsComponent|RecentsMessageHandler|handleMessage]",
"singleTaskRect: " + mSingleCountFirstTaskRect +
" multipleTaskRect: " + mMultipleCountFirstTaskRect);
@@ -83,7 +83,7 @@
class RecentsServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
- Console.log(Constants.DebugFlags.App.RecentsComponent,
+ Console.log(Constants.Log.App.RecentsComponent,
"[RecentsComponent|ServiceConnection|onServiceConnected]",
"toggleRecents: " + mToggleRecentsUponServiceBound);
mService = new Messenger(service);
@@ -103,7 +103,7 @@
@Override
public void onServiceDisconnected(ComponentName className) {
- Console.log(Constants.DebugFlags.App.RecentsComponent,
+ Console.log(Constants.Log.App.RecentsComponent,
"[RecentsComponent|ServiceConnection|onServiceDisconnected]");
mService = null;
mServiceIsBound = false;
@@ -154,7 +154,7 @@
}
public void onStart() {
- Console.log(Constants.DebugFlags.App.RecentsComponent, "[RecentsComponent|start]");
+ Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|start]");
// Try to create a long-running connection to the recents service
bindToRecentsService(false);
@@ -162,11 +162,11 @@
/** Toggles the alternate recents activity */
public void onToggleRecents(Display display, int layoutDirection, View statusBarView) {
- Console.logStartTracingTime(Constants.DebugFlags.App.TimeRecentsStartup,
- Constants.DebugFlags.App.TimeRecentsStartupKey);
- Console.logStartTracingTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
- Constants.DebugFlags.App.TimeRecentsLaunchKey);
- Console.log(Constants.DebugFlags.App.RecentsComponent, "[RecentsComponent|toggleRecents]",
+ Console.logStartTracingTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey);
+ Console.logStartTracingTime(Constants.Log.App.TimeRecentsLaunchTask,
+ Constants.Log.App.TimeRecentsLaunchKey);
+ Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|toggleRecents]",
"serviceIsBound: " + mServiceIsBound);
mStatusBarView = statusBarView;
if (!mServiceIsBound) {
@@ -192,7 +192,7 @@
}
public void onCloseRecents() {
- Console.log(Constants.DebugFlags.App.RecentsComponent, "[RecentsComponent|closeRecents]");
+ Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|closeRecents]");
if (mServiceIsBound) {
// Try and update the recents configuration
try {
@@ -400,10 +400,10 @@
mService.send(msg);
// Time this path
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
- Constants.DebugFlags.App.TimeRecentsStartupKey, "sendToggleRecents");
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
- Constants.DebugFlags.App.TimeRecentsLaunchKey, "sendToggleRecents");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey, "sendToggleRecents");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+ Constants.Log.App.TimeRecentsLaunchKey, "sendToggleRecents");
} catch (RemoteException re) {
re.printStackTrace();
}
@@ -450,8 +450,8 @@
startAlternateRecentsActivity(opts, false);
}
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
- Constants.DebugFlags.App.TimeRecentsStartupKey, "startRecentsActivity");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey, "startRecentsActivity");
mLastToggleTime = System.currentTimeMillis();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 90ea873..1d6a76c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -18,7 +18,6 @@
/**
* Constants
- * XXX: We are going to move almost all of these into a resource.
*/
public class Constants {
public static class DebugFlags {
@@ -26,12 +25,18 @@
public static final boolean Verbose = false;
public static class App {
+ // Enables the filtering of tasks according to their grouping
public static final boolean EnableTaskFiltering = false;
+ // Enables clipping of tasks against each other
public static final boolean EnableTaskStackClipping = false;
+ // Enables the use of theme colors as the task bar background
public static final boolean EnableTaskBarThemeColors = true;
+ // Enables the info pane on long-press
public static final boolean EnableInfoPane = true;
- public static final boolean EnableSearchButton = true;
-
+ // Enables the search bar layout
+ public static final boolean EnableSearchLayout = true;
+ // Enables the dynamic shadows behind each task
+ public static final boolean EnableShadows = false;
// This disables the bitmap and icon caches
public static final boolean DisableBackgroundCache = false;
// For debugging, this enables us to create mock recents tasks
@@ -40,8 +45,11 @@
public static final int SystemServicesProxyMockPackageCount = 3;
// For debugging, this defines the number of mock recents tasks to create
public static final int SystemServicesProxyMockTaskCount = 75;
+ }
+ }
- // Timing certain paths
+ public static class Log {
+ public static class App {
public static final String TimeRecentsStartupKey = "startup";
public static final String TimeRecentsLaunchKey = "launchTask";
public static final boolean TimeRecentsStartup = false;
@@ -72,6 +80,7 @@
}
}
+ /** XXX: We are going to move almost all of these into a resource once they are nailed down. */
public static class Values {
public static class App {
public static int AppWidgetHostId = 1024;
@@ -102,10 +111,5 @@
// The number of cards we see in the peek space
public static final int StackPeekNumCards = 3;
}
-
- public static class TaskView {
- public static final boolean AnimateFrontTaskBarOnEnterRecents = true;
- public static final boolean AnimateFrontTaskBarOnLeavingRecents = true;
- }
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 110130b..b74f6ac 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -22,10 +22,10 @@
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Pair;
import android.view.LayoutInflater;
@@ -38,6 +38,7 @@
import com.android.systemui.recents.views.RecentsView;
import java.util.ArrayList;
+import java.util.Set;
/** Our special app widget host */
class RecentsAppWidgetHost extends AppWidgetHost {
@@ -61,7 +62,7 @@
/* Activity */
public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks,
- RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks{
+ RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks {
FrameLayout mContainerView;
RecentsView mRecentsView;
View mEmptyView;
@@ -78,7 +79,7 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+ Console.log(Constants.Log.App.SystemUIHandshake,
"[RecentsActivity|serviceBroadcast]", action, Console.AnsiRed);
if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
// Try and unfilter and filtered stacks
@@ -134,7 +135,7 @@
/** Attempts to allocate and bind the search bar app widget */
void bindSearchBarAppWidget() {
- if (Constants.DebugFlags.App.EnableSearchButton) {
+ if (Constants.DebugFlags.App.EnableSearchLayout) {
RecentsConfiguration config = RecentsConfiguration.getInstance();
SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
@@ -152,7 +153,7 @@
ssp.unbindSearchAppWidget(mAppWidgetHost, appWidgetId);
appWidgetId = -1;
}
- Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+ Console.log(Constants.Log.App.SystemUIHandshake,
"[RecentsActivity|onCreate|settings|appWidgetId]",
"Id: " + appWidgetId,
Console.AnsiBlue);
@@ -163,7 +164,7 @@
Pair<Integer, AppWidgetProviderInfo> widgetInfo =
ssp.bindSearchAppWidget(mAppWidgetHost);
if (widgetInfo != null) {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+ Console.log(Constants.Log.App.SystemUIHandshake,
"[RecentsActivity|onCreate|searchWidget]",
"Id: " + widgetInfo.first + " Info: " + widgetInfo.second,
Console.AnsiBlue);
@@ -178,11 +179,11 @@
/** Creates the search bar app widget view */
void addSearchBarAppWidgetView() {
- if (Constants.DebugFlags.App.EnableSearchButton) {
+ if (Constants.DebugFlags.App.EnableSearchLayout) {
RecentsConfiguration config = RecentsConfiguration.getInstance();
int appWidgetId = config.searchBarAppWidgetId;
if (appWidgetId >= 0) {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+ Console.log(Constants.Log.App.SystemUIHandshake,
"[RecentsActivity|onCreate|addSearchAppWidgetView]",
"Id: " + appWidgetId,
Console.AnsiBlue);
@@ -216,11 +217,11 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Console.logDivider(Constants.DebugFlags.App.SystemUIHandshake);
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onCreate]",
+ Console.logDivider(Constants.Log.App.SystemUIHandshake);
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onCreate]",
getIntent().getAction() + " visible: " + mVisible, Console.AnsiRed);
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
- Constants.DebugFlags.App.TimeRecentsStartupKey, "onCreate");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey, "onCreate");
// Initialize the loader and the configuration
RecentsTaskLoader.initialize(this);
@@ -260,11 +261,11 @@
// Reset the task launched flag if we encounter an onNewIntent() before onStop()
mTaskLaunched = false;
- Console.logDivider(Constants.DebugFlags.App.SystemUIHandshake);
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onNewIntent]",
+ Console.logDivider(Constants.Log.App.SystemUIHandshake);
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onNewIntent]",
intent.getAction() + " visible: " + mVisible, Console.AnsiRed);
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
- Constants.DebugFlags.App.TimeRecentsStartupKey, "onNewIntent");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey, "onNewIntent");
// Initialize the loader and the configuration
RecentsTaskLoader.initialize(this);
@@ -279,7 +280,7 @@
@Override
protected void onStart() {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onStart]", "",
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onStart]", "",
Console.AnsiRed);
super.onStart();
mAppWidgetHost.startListening();
@@ -288,14 +289,14 @@
@Override
protected void onResume() {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onResume]", "",
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onResume]", "",
Console.AnsiRed);
super.onResume();
}
@Override
public void onAttachedToWindow() {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+ Console.log(Constants.Log.App.SystemUIHandshake,
"[RecentsActivity|onAttachedToWindow]", "",
Console.AnsiRed);
super.onAttachedToWindow();
@@ -309,11 +310,14 @@
filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(mScreenOffReceiver, filter);
+
+ // Register any broadcast receivers for the task loader
+ RecentsTaskLoader.getInstance().registerReceivers(this, mRecentsView);
}
@Override
public void onDetachedFromWindow() {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+ Console.log(Constants.Log.App.SystemUIHandshake,
"[RecentsActivity|onDetachedFromWindow]", "",
Console.AnsiRed);
super.onDetachedFromWindow();
@@ -321,18 +325,19 @@
// Unregister any broadcast receivers we have registered
unregisterReceiver(mServiceBroadcastReceiver);
unregisterReceiver(mScreenOffReceiver);
+ RecentsTaskLoader.getInstance().unregisterReceivers();
}
@Override
protected void onPause() {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onPause]", "",
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onPause]", "",
Console.AnsiRed);
super.onPause();
}
@Override
protected void onStop() {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onStop]", "",
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onStop]", "",
Console.AnsiRed);
super.onStop();
@@ -343,7 +348,7 @@
@Override
protected void onDestroy() {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onDestroy]", "",
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onDestroy]", "",
Console.AnsiRed);
super.onDestroy();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index d1a3954..463cf74 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -49,6 +49,8 @@
public int taskStackScrollDismissInfoPaneDistance;
public int taskStackMaxDim;
public int taskViewInfoPaneAnimDuration;
+ public int taskViewRemoveAnimDuration;
+ public int taskViewRemoveAnimTranslationXPx;
public int taskViewTranslationZMinPx;
public int taskViewTranslationZIncrementPx;
public int taskViewRoundedCornerRadiusPx;
@@ -88,7 +90,7 @@
Configuration.ORIENTATION_LANDSCAPE;
transposeSearchLayoutWithOrientation =
res.getBoolean(R.bool.recents_transpose_search_layout_with_orientation);
- Console.log(Constants.DebugFlags.UI.MeasureAndLayout,
+ Console.log(Constants.Log.UI.MeasureAndLayout,
"[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait",
Console.AnsiGreen);
@@ -108,6 +110,10 @@
taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim);
taskViewInfoPaneAnimDuration =
res.getInteger(R.integer.recents_animate_task_view_info_pane_duration);
+ taskViewRemoveAnimDuration =
+ res.getInteger(R.integer.recents_animate_task_view_remove_duration);
+ taskViewRemoveAnimTranslationXPx =
+ res.getDimensionPixelSize(R.dimen.recents_task_view_remove_anim_translation_x);
taskViewRoundedCornerRadiusPx =
res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
taskViewTranslationZMinPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
@@ -174,7 +180,7 @@
*/
public void getSearchBarBounds(int width, int height, Rect searchBarSpaceBounds) {
// Return empty rects if search is not enabled
- if (!Constants.DebugFlags.App.EnableSearchButton) {
+ if (!Constants.DebugFlags.App.EnableSearchLayout) {
searchBarSpaceBounds.set(0, 0, 0, 0);
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsPackageMonitor.java
new file mode 100644
index 0000000..4e620b6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsPackageMonitor.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Looper;
+import com.android.internal.content.PackageMonitor;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * The package monitor listens for changes from PackageManager to update the contents of the Recents
+ * list.
+ */
+public class RecentsPackageMonitor extends PackageMonitor {
+ public interface PackageCallbacks {
+ public void onComponentRemoved(Set<ComponentName> cns);
+ }
+
+ PackageCallbacks mCb;
+ List<ActivityManager.RecentTaskInfo> mTasks;
+ SystemServicesProxy mSsp;
+
+ public RecentsPackageMonitor(Context context) {
+ mSsp = new SystemServicesProxy(context);
+ }
+
+ /** Registers the broadcast receivers with the specified callbacks. */
+ public void register(Context context, PackageCallbacks cb) {
+ mCb = cb;
+ register(context, Looper.getMainLooper(), false);
+ }
+
+ /** Unregisters the broadcast receivers. */
+ @Override
+ public void unregister() {
+ super.unregister();
+ mTasks.clear();
+ }
+
+ /** Sets the list of tasks to match against package broadcast changes. */
+ void setTasks(List<ActivityManager.RecentTaskInfo> tasks) {
+ mTasks = tasks;
+ }
+
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ if (mCb == null) return;
+
+ // Identify all the tasks that should be removed as a result of the package being removed.
+ // Using a set to ensure that we callback once per unique component.
+ HashSet<ComponentName> componentsToRemove = new HashSet<ComponentName>();
+ for (ActivityManager.RecentTaskInfo t : mTasks) {
+ ComponentName cn = t.baseIntent.getComponent();
+ if (cn.getPackageName().equals(packageName)) {
+ componentsToRemove.add(cn);
+ }
+ }
+ // Notify our callbacks that the components no longer exist
+ mCb.onComponentRemoved(componentsToRemove);
+ }
+
+ @Override
+ public boolean onPackageChanged(String packageName, int uid, String[] components) {
+ onPackageModified(packageName);
+ return true;
+ }
+
+ @Override
+ public void onPackageModified(String packageName) {
+ if (mCb == null) return;
+
+ // Identify all the tasks that should be removed as a result of the package being removed.
+ // Using a set to ensure that we callback once per unique component.
+ HashSet<ComponentName> componentsKnownToExist = new HashSet<ComponentName>();
+ HashSet<ComponentName> componentsToRemove = new HashSet<ComponentName>();
+ for (ActivityManager.RecentTaskInfo t : mTasks) {
+ ComponentName cn = t.baseIntent.getComponent();
+ if (cn.getPackageName().equals(packageName)) {
+ if (componentsKnownToExist.contains(cn)) {
+ // If we know that the component still exists in the package, then skip
+ continue;
+ }
+ if (mSsp.getActivityInfo(cn) != null) {
+ componentsKnownToExist.add(cn);
+ } else {
+ componentsToRemove.add(cn);
+ }
+ }
+ }
+ // Notify our callbacks that the components no longer exist
+ mCb.onComponentRemoved(componentsToRemove);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index 0c6ed84..837cb34 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -45,7 +45,7 @@
@Override
public void handleMessage(Message msg) {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+ Console.log(Constants.Log.App.SystemUIHandshake,
"[RecentsService|handleMessage]", msg);
Context context = mContext.get();
@@ -115,10 +115,10 @@
context.sendBroadcast(intent);
// Time this path
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
- Constants.DebugFlags.App.TimeRecentsStartupKey, "receivedToggleRecents");
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
- Constants.DebugFlags.App.TimeRecentsLaunchKey, "receivedToggleRecents");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey, "receivedToggleRecents");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+ Constants.Log.App.TimeRecentsLaunchKey, "receivedToggleRecents");
}
}
}
@@ -131,31 +131,31 @@
@Override
public void onCreate() {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onCreate]");
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onCreate]");
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onBind]");
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onBind]");
return mSystemUIMessenger.getBinder();
}
@Override
public boolean onUnbind(Intent intent) {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onUnbind]");
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onUnbind]");
return super.onUnbind(intent);
}
@Override
public void onRebind(Intent intent) {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onRebind]");
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onRebind]");
super.onRebind(intent);
}
@Override
public void onDestroy() {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onDestroy]");
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onDestroy]");
super.onDestroy();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index 4a19027..f3e411f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -51,7 +51,7 @@
/** Adds a new task to the load queue */
void addTask(Task t, boolean forceLoad) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader, " [TaskResourceLoadQueue|addTask]");
+ Console.log(Constants.Log.App.TaskDataLoader, " [TaskResourceLoadQueue|addTask]");
if (!mQueue.contains(t)) {
mQueue.add(t);
}
@@ -68,7 +68,7 @@
* force reloaded.
*/
Pair<Task, Boolean> nextTask() {
- Console.log(Constants.DebugFlags.App.TaskDataLoader, " [TaskResourceLoadQueue|nextTask]");
+ Console.log(Constants.Log.App.TaskDataLoader, " [TaskResourceLoadQueue|nextTask]");
Task task = mQueue.poll();
Boolean forceLoadTask = null;
if (task != null) {
@@ -82,14 +82,14 @@
/** Removes a task from the load queue */
void removeTask(Task t) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader, " [TaskResourceLoadQueue|removeTask]");
+ Console.log(Constants.Log.App.TaskDataLoader, " [TaskResourceLoadQueue|removeTask]");
mQueue.remove(t);
mForceLoadSet.remove(t.key);
}
/** Clears all the tasks from the load queue */
void clearTasks() {
- Console.log(Constants.DebugFlags.App.TaskDataLoader, " [TaskResourceLoadQueue|clearTasks]");
+ Console.log(Constants.Log.App.TaskDataLoader, " [TaskResourceLoadQueue|clearTasks]");
mQueue.clear();
mForceLoadSet.clear();
}
@@ -132,7 +132,7 @@
/** Restarts the loader thread */
void start(Context context) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|start]");
+ Console.log(Constants.Log.App.TaskDataLoader, "[TaskResourceLoader|start]");
mContext = context;
mCancelled = false;
mSystemServicesProxy = new SystemServicesProxy(context);
@@ -144,7 +144,7 @@
/** Requests the loader thread to stop after the current iteration */
void stop() {
- Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|stop]");
+ Console.log(Constants.Log.App.TaskDataLoader, "[TaskResourceLoader|stop]");
// Mark as cancelled for the thread to pick up
mCancelled = true;
mSystemServicesProxy = null;
@@ -158,10 +158,10 @@
@Override
public void run() {
while (true) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[TaskResourceLoader|run|" + Thread.currentThread().getId() + "]");
if (mCancelled) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[TaskResourceLoader|cancel|" + Thread.currentThread().getId() + "]");
// We have to unset the context here, since the background thread may be using it
// when we call stop()
@@ -169,7 +169,7 @@
// If we are cancelled, then wait until we are started again
synchronized(mLoadThread) {
try {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[TaskResourceLoader|waitOnLoadThreadCancelled]");
mLoadThread.wait();
} catch (InterruptedException ie) {
@@ -186,7 +186,7 @@
if (t != null) {
Drawable loadIcon = mApplicationIconCache.get(t.key);
Bitmap loadThumbnail = mThumbnailCache.get(t.key);
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
" [TaskResourceLoader|load]",
t + " icon: " + loadIcon + " thumbnail: " + loadThumbnail +
" forceLoad: " + forceLoadTask);
@@ -197,7 +197,7 @@
Drawable icon = ssp.getActivityIcon(info, t.userId);
if (!mCancelled) {
if (icon != null) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
" [TaskResourceLoader|loadIcon]",
icon);
loadIcon = icon;
@@ -210,7 +210,7 @@
Bitmap thumbnail = ssp.getTaskThumbnail(t.key.id);
if (!mCancelled) {
if (thumbnail != null) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
" [TaskResourceLoader|loadThumbnail]",
thumbnail);
thumbnail.setHasAlpha(false);
@@ -240,7 +240,7 @@
if (!mCancelled && mLoadQueue.isEmpty()) {
synchronized(mLoadQueue) {
try {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[TaskResourceLoader|waitOnLoadQueue]");
mWaitingOnLoadQueue = true;
mLoadQueue.wait();
@@ -300,6 +300,8 @@
TaskResourceLoadQueue mLoadQueue;
TaskResourceLoader mLoader;
+ RecentsPackageMonitor mPackageMonitor;
+
int mMaxThumbnailCacheSize;
int mMaxIconCacheSize;
@@ -319,12 +321,13 @@
int thumbnailCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 :
mMaxThumbnailCacheSize;
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[RecentsTaskLoader|init]", "thumbnailCache: " + thumbnailCacheSize +
" iconCache: " + iconCacheSize);
// Initialize the proxy, cache and loaders
mSystemServicesProxy = new SystemServicesProxy(context);
+ mPackageMonitor = new RecentsPackageMonitor(context);
mLoadQueue = new TaskResourceLoadQueue();
mApplicationIconCache = new DrawableLruCache(iconCacheSize);
mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);
@@ -336,7 +339,7 @@
mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
mDefaultThumbnail.eraseColor(0x00000000);
mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon);
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[RecentsTaskLoader|defaultBitmaps]",
"icon: " + mDefaultApplicationIcon + " thumbnail: " + mDefaultThumbnail, Console.AnsiRed);
}
@@ -366,10 +369,10 @@
List<ActivityManager.RecentTaskInfo> tasks =
ssp.getRecentTasks(25, UserHandle.CURRENT.getIdentifier());
Collections.reverse(tasks);
- Console.log(Constants.DebugFlags.App.TimeSystemCalls,
+ Console.log(Constants.Log.App.TimeSystemCalls,
"[RecentsTaskLoader|getRecentTasks]",
"" + (System.currentTimeMillis() - t1) + "ms");
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[RecentsTaskLoader|tasks]", "" + tasks.size());
// Remove home/recents tasks
@@ -396,7 +399,7 @@
SpaceNode reload(Context context, int preloadCount) {
long t1 = System.currentTimeMillis();
- Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
+ Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
Resources res = context.getResources();
ArrayList<Task> tasksToForceLoad = new ArrayList<Task>();
TaskStack stack = new TaskStack(context);
@@ -435,7 +438,7 @@
// Preload the specified number of apps
if (i >= (taskCount - preloadCount)) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[RecentsTaskLoader|preloadTask]",
"i: " + i + " task: " + t.baseIntent.getComponent().getPackageName());
@@ -467,7 +470,7 @@
}
}
if (task.thumbnail == null) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[RecentsTaskLoader|loadingTaskThumbnail]");
task.thumbnail = ssp.getTaskThumbnail(task.key.id);
if (task.thumbnail != null) {
@@ -480,11 +483,11 @@
}
// Add the task to the stack
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
" [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName());
stack.addTask(task);
}
- Console.log(Constants.DebugFlags.App.TimeSystemCalls,
+ Console.log(Constants.Log.App.TimeSystemCalls,
"[RecentsTaskLoader|getAllTaskTopThumbnail]",
"" + (System.currentTimeMillis() - t1) + "ms");
@@ -492,10 +495,10 @@
// Get all the stacks
t1 = System.currentTimeMillis();
List<ActivityManager.StackInfo> stackInfos = ams.getAllStackInfos();
- Console.log(Constants.DebugFlags.App.TimeSystemCalls, "[RecentsTaskLoader|getAllStackInfos]", "" + (System.currentTimeMillis() - t1) + "ms");
- Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|stacks]", "" + tasks.size());
+ Console.log(Constants.Log.App.TimeSystemCalls, "[RecentsTaskLoader|getAllStackInfos]", "" + (System.currentTimeMillis() - t1) + "ms");
+ Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|stacks]", "" + tasks.size());
for (ActivityManager.StackInfo s : stackInfos) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader, " [RecentsTaskLoader|stack]", s.toString());
+ Console.log(Constants.Log.App.TaskDataLoader, " [RecentsTaskLoader|stack]", s.toString());
if (stacks.containsKey(s.stackId)) {
stacks.get(s.stackId).setRect(s.bounds);
}
@@ -510,6 +513,9 @@
mLoadQueue.addTask(t, true);
}
+ // Update the package monitor with the list of packages to listen for
+ mPackageMonitor.setTasks(tasks);
+
return root;
}
@@ -518,7 +524,7 @@
Drawable applicationIcon = mApplicationIconCache.get(t.key);
Bitmap thumbnail = mThumbnailCache.get(t.key);
- Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|loadTask]",
+ Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|loadTask]",
t + " applicationIcon: " + applicationIcon + " thumbnail: " + thumbnail +
" thumbnailCacheSize: " + mThumbnailCache.size());
@@ -539,7 +545,7 @@
/** Releases the task resource data back into the pool. */
public void unloadTaskData(Task t) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[RecentsTaskLoader|unloadTask]", t +
" thumbnailCacheSize: " + mThumbnailCache.size());
@@ -549,7 +555,7 @@
/** Completely removes the resource data from the pool. */
public void deleteTaskData(Task t) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[RecentsTaskLoader|deleteTask]", t);
mLoadQueue.removeTask(t);
@@ -560,13 +566,28 @@
/** Stops the task loader and clears all pending tasks */
void stopLoader() {
- Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|stopLoader]");
+ Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|stopLoader]");
mLoader.stop();
mLoadQueue.clearTasks();
}
+ /** Registers any broadcast receivers. */
+ public void registerReceivers(Context context, RecentsPackageMonitor.PackageCallbacks cb) {
+ // Register the broadcast receiver to handle messages related to packages being added/removed
+ mPackageMonitor.register(context, cb);
+ }
+
+ /** Unregisters any broadcast receivers. */
+ public void unregisterReceivers() {
+ mPackageMonitor.unregister();
+ }
+
+ /**
+ * Handles signals from the system, trimming memory when requested to prevent us from running
+ * out of memory.
+ */
void onTrimMemory(int level) {
- Console.log(Constants.DebugFlags.App.Memory, "[RecentsTaskLoader|onTrimMemory]",
+ Console.log(Constants.Log.App.Memory, "[RecentsTaskLoader|onTrimMemory]",
Console.trimMemoryLevelToString(level));
switch (level) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index c3b8a20..b41555f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -180,7 +180,7 @@
*/
public ActivityInfo getActivityInfo(ComponentName cn, int userId) {
if (mIpm == null) return null;
- if (Constants.DebugFlags.App.EnableSystemServicesProxy) return null;
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) return new ActivityInfo();
try {
return mIpm.getActivityInfo(cn, PackageManager.GET_META_DATA, userId);
@@ -197,7 +197,7 @@
*/
public ActivityInfo getActivityInfo(ComponentName cn) {
if (mPm == null) return null;
- if (Constants.DebugFlags.App.EnableSystemServicesProxy) return null;
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) return new ActivityInfo();
try {
return mPm.getActivityInfo(cn, PackageManager.GET_META_DATA);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index c2e8275..8168619 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -19,6 +19,7 @@
import android.app.ActivityOptions;
import android.app.TaskStackBuilder;
import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
@@ -33,19 +34,22 @@
import com.android.systemui.recents.Console;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.RecentsPackageMonitor;
import com.android.systemui.recents.RecentsTaskLoader;
import com.android.systemui.recents.model.SpaceNode;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
import java.util.ArrayList;
+import java.util.Set;
/**
* This view is the the top level layout that contains TaskStacks (which are laid out according
* to their SpaceNode bounds.
*/
-public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks {
+public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks,
+ RecentsPackageMonitor.PackageCallbacks {
/** The RecentsView callbacks */
public interface RecentsViewCallbacks {
@@ -124,7 +128,7 @@
/** Adds the search bar */
public void setSearchBar(View searchBar) {
// Create the search bar (and hide it if we have no recent tasks)
- if (Constants.DebugFlags.App.EnableSearchButton) {
+ if (Constants.DebugFlags.App.EnableSearchLayout) {
// Remove the previous search bar if one exists
if (mSearchBar != null && indexOfChild(mSearchBar) > -1) {
removeView(mSearchBar);
@@ -135,7 +139,7 @@
mSearchBar.setVisibility(mHasTasks ? View.VISIBLE : View.GONE);
addView(mSearchBar);
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsView|setSearchBar]",
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsView|setSearchBar]",
"" + (mSearchBar.getVisibility() == View.VISIBLE),
Console.AnsiBlue);
}
@@ -152,10 +156,10 @@
int height = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|measure]",
+ Console.log(Constants.Log.UI.MeasureAndLayout, "[RecentsView|measure]",
"width: " + width + " height: " + height, Console.AnsiGreen);
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
- Constants.DebugFlags.App.TimeRecentsStartupKey, "RecentsView.onMeasure");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey, "RecentsView.onMeasure");
// Get the search bar bounds and measure the search bar layout
RecentsConfiguration config = RecentsConfiguration.getInstance();
@@ -194,10 +198,10 @@
*/
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|layout]",
+ Console.log(Constants.Log.UI.MeasureAndLayout, "[RecentsView|layout]",
new Rect(left, top, right, bottom) + " changed: " + changed, Console.AnsiGreen);
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
- Constants.DebugFlags.App.TimeRecentsStartupKey, "RecentsView.onLayout");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey, "RecentsView.onLayout");
// Get the search bar bounds so that we lay it out
RecentsConfiguration config = RecentsConfiguration.getInstance();
@@ -232,14 +236,14 @@
@Override
protected void dispatchDraw(Canvas canvas) {
- Console.log(Constants.DebugFlags.UI.Draw, "[RecentsView|dispatchDraw]", "",
+ Console.log(Constants.Log.UI.Draw, "[RecentsView|dispatchDraw]", "",
Console.AnsiPurple);
super.dispatchDraw(canvas);
}
@Override
protected boolean fitSystemWindows(Rect insets) {
- Console.log(Constants.DebugFlags.UI.MeasureAndLayout,
+ Console.log(Constants.Log.UI.MeasureAndLayout,
"[RecentsView|fitSystemWindows]", "insets: " + insets, Console.AnsiGreen);
// Update the configuration with the latest system insets and trigger a relayout
@@ -359,16 +363,16 @@
}
}
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
- Constants.DebugFlags.App.TimeRecentsLaunchKey, "startActivity");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+ Constants.Log.App.TimeRecentsLaunchKey, "startActivity");
}
};
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
- Constants.DebugFlags.App.TimeRecentsLaunchKey, "onTaskLaunched");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+ Constants.Log.App.TimeRecentsLaunchKey, "onTaskLaunched");
// Launch the app right away if there is no task view, otherwise, animate the icon out first
- if (tv == null || !Constants.Values.TaskView.AnimateFrontTaskBarOnLeavingRecents) {
+ if (tv == null) {
post(launchRunnable);
} else {
tv.animateOnLeavingRecents(launchRunnable);
@@ -385,4 +389,19 @@
TaskStackBuilder.create(getContext())
.addNextIntentWithParentStack(intent).startActivities();
}
+
+ /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
+
+ @Override
+ public void onComponentRemoved(Set<ComponentName> cns) {
+ // Propagate this event down to each task stack view
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ if (child instanceof TaskStackView) {
+ TaskStackView stackView = (TaskStackView) child;
+ stackView.onComponentRemoved(cns);
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
index 21ef9ff..c34300c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
@@ -178,7 +178,7 @@
}
public boolean onInterceptTouchEvent(MotionEvent ev) {
- Console.log(Constants.DebugFlags.UI.TouchEvents,
+ Console.log(Constants.Log.UI.TouchEvents,
"[SwipeHelper|interceptTouchEvent]",
Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
final int action = ev.getAction();
@@ -291,7 +291,7 @@
}
public boolean onTouchEvent(MotionEvent ev) {
- Console.log(Constants.DebugFlags.UI.TouchEvents,
+ Console.log(Constants.Log.UI.TouchEvents,
"[SwipeHelper|touchEvent]",
Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index ce43b5a..ad0f2f82 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -18,10 +18,10 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
+import android.content.ComponentName;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
@@ -40,6 +40,7 @@
import com.android.systemui.recents.Console;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.RecentsPackageMonitor;
import com.android.systemui.recents.RecentsTaskLoader;
import com.android.systemui.recents.Utilities;
import com.android.systemui.recents.model.Task;
@@ -47,12 +48,13 @@
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Set;
/* The visual representation of a task stack view */
public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCallbacks,
TaskView.TaskViewCallbacks, ViewPool.ViewPoolConsumer<TaskView, Task>,
- View.OnClickListener, View.OnLongClickListener {
+ View.OnClickListener, View.OnLongClickListener, RecentsPackageMonitor.PackageCallbacks {
/** The TaskView callbacks */
interface TaskStackViewCallbacks {
@@ -110,7 +112,7 @@
requestSynchronizeStackViewsWithModel(0);
}
void requestSynchronizeStackViewsWithModel(int duration) {
- Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
+ Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
"[TaskStackView|requestSynchronize]", "" + duration + "ms", Console.AnsiYellow);
if (!mStackViewsDirty) {
invalidate();
@@ -215,7 +217,7 @@
/** Synchronizes the views with the model */
void synchronizeStackViewsWithModel() {
- Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
+ Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
"[TaskStackView|synchronizeViewsWithModel]",
"mStackViewsDirty: " + mStackViewsDirty, Console.AnsiYellow);
if (mStackViewsDirty) {
@@ -271,7 +273,7 @@
}
}
- Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
+ Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
" [TaskStackView|viewChildren]", "" + getChildCount());
mStackViewsAnimationDuration = 0;
@@ -429,7 +431,7 @@
}
// Debug logging
- if (Constants.DebugFlags.UI.MeasureAndLayout) {
+ if (Constants.Log.UI.MeasureAndLayout) {
Console.log(" [TaskStack|minScroll] " + mMinScroll);
Console.log(" [TaskStack|maxScroll] " + mMaxScroll);
}
@@ -456,7 +458,7 @@
/** Enables the hw layers and increments the hw layer requirement ref count */
void addHwLayersRefCount(String reason) {
- Console.log(Constants.DebugFlags.UI.HwLayers,
+ Console.log(Constants.Log.UI.HwLayers,
"[TaskStackView|addHwLayersRefCount] refCount: " +
mHwLayersRefCount + "->" + (mHwLayersRefCount + 1) + " " + reason);
if (mHwLayersRefCount == 0) {
@@ -473,7 +475,7 @@
/** Decrements the hw layer requirement ref count and disables the hw layers when we don't
need them anymore. */
void decHwLayersRefCount(String reason) {
- Console.log(Constants.DebugFlags.UI.HwLayers,
+ Console.log(Constants.Log.UI.HwLayers,
"[TaskStackView|decHwLayersRefCount] refCount: " +
mHwLayersRefCount + "->" + (mHwLayersRefCount - 1) + " " + reason);
mHwLayersRefCount--;
@@ -515,7 +517,7 @@
@Override
public void dispatchDraw(Canvas canvas) {
- Console.log(Constants.DebugFlags.UI.Draw, "[TaskStackView|dispatchDraw]", "",
+ Console.log(Constants.Log.UI.Draw, "[TaskStackView|dispatchDraw]", "",
Console.AnsiPurple);
synchronizeStackViewsWithModel();
super.dispatchDraw(canvas);
@@ -568,7 +570,7 @@
int smallestDimension = Math.min(width, height);
int padding = (int) (Constants.Values.TaskStackView.StackPaddingPct * smallestDimension / 2f);
- if (Constants.DebugFlags.App.EnableSearchButton) {
+ if (Constants.DebugFlags.App.EnableSearchLayout) {
mStackRect.top += padding;
mStackRect.left += padding;
mStackRect.right -= padding;
@@ -600,7 +602,7 @@
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
- Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[TaskStackView|measure]",
+ Console.log(Constants.Log.UI.MeasureAndLayout, "[TaskStackView|measure]",
"width: " + width + " height: " + height +
" awaitingFirstLayout: " + mAwaitingFirstLayout, Console.AnsiGreen);
@@ -611,7 +613,7 @@
computeRects(width, height, taskStackBounds.left, config.systemInsets.bottom);
// Debug logging
- if (Constants.DebugFlags.UI.MeasureAndLayout) {
+ if (Constants.Log.UI.MeasureAndLayout) {
Console.log(" [TaskStack|fullRect] " + mRect);
Console.log(" [TaskStack|stackRect] " + mStackRect);
Console.log(" [TaskStack|stackRectSansPeek] " + mStackRectSansPeek);
@@ -626,8 +628,7 @@
synchronizeStackViewsWithModel();
// Animate the task bar of the first task view
- if (config.launchedWithThumbnailAnimation &&
- Constants.Values.TaskView.AnimateFrontTaskBarOnEnterRecents) {
+ if (config.launchedWithThumbnailAnimation) {
TaskView tv = (TaskView) getChildAt(getChildCount() - 1);
if (tv != null) {
tv.animateOnEnterRecents();
@@ -653,11 +654,11 @@
*/
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[TaskStackView|layout]",
+ Console.log(Constants.Log.UI.MeasureAndLayout, "[TaskStackView|layout]",
"" + new Rect(left, top, right, bottom), Console.AnsiGreen);
// Debug logging
- if (Constants.DebugFlags.UI.MeasureAndLayout) {
+ if (Constants.Log.UI.MeasureAndLayout) {
Console.log(" [TaskStack|fullRect] " + mRect);
Console.log(" [TaskStack|stackRect] " + mStackRect);
Console.log(" [TaskStack|stackRectSansPeek] " + mStackRectSansPeek);
@@ -707,9 +708,24 @@
}
}
+ // Update the min/max scroll and animate other task views into their new positions
updateMinMaxScroll(true);
int movement = (int) (Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height());
requestSynchronizeStackViewsWithModel(Utilities.calculateTranslationAnimationDuration(movement));
+
+ // If there are no remaining tasks, then either unfilter the current stack, or just close
+ // the activity if there are no filtered stacks
+ if (mStack.getTaskCount() == 0) {
+ boolean shouldFinishActivity = true;
+ if (mStack.hasFilteredTasks()) {
+ mStack.unfilterTasks();
+ shouldFinishActivity = (mStack.getTaskCount() == 0);
+ }
+ if (shouldFinishActivity) {
+ Activity activity = (Activity) getContext();
+ activity.finish();
+ }
+ }
}
/**
@@ -911,7 +927,7 @@
@Override
public TaskView createView(Context context) {
- Console.log(Constants.DebugFlags.ViewPool.PoolCallbacks, "[TaskStackView|createPoolView]");
+ Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|createPoolView]");
return (TaskView) mInflater.inflate(R.layout.recents_task_view, this, false);
}
@@ -919,7 +935,7 @@
public void prepareViewToEnterPool(TaskView tv) {
Task task = tv.getTask();
tv.resetViewProperties();
- Console.log(Constants.DebugFlags.ViewPool.PoolCallbacks, "[TaskStackView|returnToPool]",
+ Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|returnToPool]",
tv.getTask() + " tv: " + tv);
// Report that this tasks's data is no longer being used
@@ -935,7 +951,7 @@
@Override
public void prepareViewToLeavePool(TaskView tv, Task prepareData, boolean isNewView) {
- Console.log(Constants.DebugFlags.ViewPool.PoolCallbacks, "[TaskStackView|leavePool]",
+ Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|leavePool]",
"isNewView: " + isNewView);
// Setup and attach the view to the window
@@ -958,7 +974,7 @@
}
// Add/attach the view to the hierarchy
- Console.log(Constants.DebugFlags.ViewPool.PoolCallbacks, " [TaskStackView|insertIndex]",
+ Console.log(Constants.Log.ViewPool.PoolCallbacks, " [TaskStackView|insertIndex]",
"" + insertIndex);
if (isNewView) {
addView(tv, insertIndex);
@@ -988,7 +1004,7 @@
@Override
public void onTaskIconClicked(TaskView tv) {
- Console.log(Constants.DebugFlags.UI.ClickEvents, "[TaskStack|Clicked|Icon]",
+ Console.log(Constants.Log.UI.ClickEvents, "[TaskStack|Clicked|Icon]",
tv.getTask() + " is currently filtered: " + mStack.hasFilteredTasks(),
Console.AnsiCyan);
if (Constants.DebugFlags.App.EnableTaskFiltering) {
@@ -1024,7 +1040,7 @@
public void onClick(View v) {
TaskView tv = (TaskView) v;
Task task = tv.getTask();
- Console.log(Constants.DebugFlags.UI.ClickEvents, "[TaskStack|Clicked|Thumbnail]",
+ Console.log(Constants.Log.UI.ClickEvents, "[TaskStack|Clicked|Thumbnail]",
task + " cb: " + mCb);
// Close any open info panes if the user taps on another task
@@ -1072,6 +1088,32 @@
tv.showInfoPane(new Rect(0, 0, 0, (int) overlapHeight));
return true;
}
+
+ /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
+
+ @Override
+ public void onComponentRemoved(Set<ComponentName> cns) {
+ // For other tasks, just remove them directly if they no longer exist
+ ArrayList<Task> tasks = mStack.getTasks();
+ for (int i = tasks.size() - 1; i >= 0; i--) {
+ final Task t = tasks.get(i);
+ if (cns.contains(t.key.baseIntent.getComponent())) {
+ TaskView tv = getChildViewForTask(t);
+ if (tv != null) {
+ // For visible children, defer removing the task until after the animation
+ tv.animateRemoval(new Runnable() {
+ @Override
+ public void run() {
+ mStack.removeTask(t);
+ }
+ });
+ } else {
+ // Otherwise, remove the task from the stack immediately
+ mStack.removeTask(t);
+ }
+ }
+ }
+ }
}
/* Handles touch events */
@@ -1149,7 +1191,7 @@
/** Touch preprocessing for handling below */
public boolean onInterceptTouchEvent(MotionEvent ev) {
- Console.log(Constants.DebugFlags.UI.TouchEvents,
+ Console.log(Constants.Log.UI.TouchEvents,
"[TaskStackViewTouchHandler|interceptTouchEvent]",
Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
@@ -1233,7 +1275,7 @@
/** Handles touch events once we have intercepted them */
public boolean onTouchEvent(MotionEvent ev) {
- Console.log(Constants.DebugFlags.UI.TouchEvents,
+ Console.log(Constants.Log.UI.TouchEvents,
"[TaskStackViewTouchHandler|touchEvent]",
Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
@@ -1336,7 +1378,7 @@
Math.abs((float) velocity / mMaximumVelocity)) *
Constants.Values.TaskStackView.TaskStackOverscrollRange);
- Console.log(Constants.DebugFlags.UI.TouchEvents,
+ Console.log(Constants.Log.UI.TouchEvents,
"[TaskStackViewTouchHandler|fling]",
"scroll: " + mSv.getStackScroll() + " velocity: " + velocity +
" maxVelocity: " + mMaximumVelocity +
@@ -1434,7 +1476,6 @@
public void onChildDismissed(View v) {
TaskView tv = (TaskView) v;
Task task = tv.getTask();
- Activity activity = (Activity) mSv.getContext();
// Remove the task from the view
mSv.mStack.removeTask(task);
@@ -1446,19 +1487,6 @@
// Remove the task from activity manager
RecentsTaskLoader.getInstance().getSystemServicesProxy().removeTask(tv.getTask().key.id);
- // If there are no remaining tasks, then either unfilter the current stack, or just close
- // the activity if there are no filtered stacks
- if (mSv.mStack.getTaskCount() == 0) {
- boolean shouldFinishActivity = true;
- if (mSv.mStack.hasFilteredTasks()) {
- mSv.mStack.unfilterTasks();
- shouldFinishActivity = (mSv.mStack.getTaskCount() == 0);
- }
- if (shouldFinishActivity) {
- activity.finish();
- }
- }
-
// Disable HW layers
mSv.decHwLayersRefCount("swipeComplete");
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 801de24..b03f389 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -146,13 +146,17 @@
if (duration > 0) {
if (animateFromTransform != null) {
setTranslationY(animateFromTransform.translationY);
- setTranslationZ(Math.max(minZ, minZ + (animateFromTransform.t * incZ)));
+ if (Constants.DebugFlags.App.EnableShadows) {
+ setTranslationZ(Math.max(minZ, minZ + (animateFromTransform.t * incZ)));
+ }
setScaleX(animateFromTransform.scale);
setScaleY(animateFromTransform.scale);
setAlpha(animateFromTransform.alpha);
}
+ if (Constants.DebugFlags.App.EnableShadows) {
+ animate().translationZ(Math.max(minZ, minZ + (toTransform.t * incZ)));
+ }
animate().translationY(toTransform.translationY)
- .translationZ(Math.max(minZ, minZ + (toTransform.t * incZ)))
.scaleX(toTransform.scale)
.scaleY(toTransform.scale)
.alpha(toTransform.alpha)
@@ -168,7 +172,9 @@
.start();
} else {
setTranslationY(toTransform.translationY);
- setTranslationZ(Math.max(minZ, minZ + (toTransform.t * incZ)));
+ if (Constants.DebugFlags.App.EnableShadows) {
+ setTranslationZ(Math.max(minZ, minZ + (toTransform.t * incZ)));
+ }
setScaleX(toTransform.scale);
setScaleY(toTransform.scale);
setAlpha(toTransform.alpha);
@@ -181,7 +187,9 @@
void resetViewProperties() {
setTranslationX(0f);
setTranslationY(0f);
- setTranslationZ(0f);
+ if (Constants.DebugFlags.App.EnableShadows) {
+ setTranslationZ(0f);
+ }
setScaleX(1f);
setScaleY(1f);
setAlpha(1f);
@@ -238,6 +246,24 @@
.start();
}
+ /** Animates the deletion of this task view */
+ public void animateRemoval(final Runnable r) {
+ RecentsConfiguration config = RecentsConfiguration.getInstance();
+ animate().translationX(config.taskViewRemoveAnimTranslationXPx)
+ .alpha(0f)
+ .setStartDelay(0)
+ .setInterpolator(BakedBezierInterpolator.INSTANCE)
+ .setDuration(config.taskViewRemoveAnimDuration)
+ .withLayer()
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ post(r);
+ }
+ })
+ .start();
+ }
+
/** Returns the rect we want to clip (it may not be the full rect) */
Rect getClippingRect(Rect outRect) {
getHitRect(outRect);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 1c88ea7..91df9ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -38,6 +38,7 @@
public abstract class ActivatableNotificationView extends ExpandableOutlineView {
private static final long DOUBLETAP_TIMEOUT_MS = 1000;
+ private static final int BACKGROUND_ANIMATION_LENGTH_MS = 220;
private boolean mDimmed;
@@ -174,12 +175,14 @@
private void makeInactive() {
if (mActivated) {
// Make sure that we clear the hotspot from the center.
- mBackgroundDimmed.setHotspot(0, getWidth() / 2, getActualHeight() / 2);
- mBackgroundDimmed.removeHotspot(0);
+ if (mBackgroundDimmed != null) {
+ mBackgroundDimmed.setHotspot(0, getWidth() / 2, getActualHeight() / 2);
+ mBackgroundDimmed.removeHotspot(0);
+ }
mActivated = false;
}
if (mOnActivatedListener != null) {
- mOnActivatedListener.onReset(this);
+ mOnActivatedListener.onActivationReset(this);
}
removeCallbacks(mTapTimeoutRunnable);
}
@@ -189,12 +192,6 @@
&& Math.abs(event.getY() - mDownY) < mTouchSlop;
}
- /**
- * Sets the notification as dimmed, meaning that it will appear in a more gray variant.
- *
- * @param dimmed Whether the notification should be dimmed.
- * @param fade Whether an animation should be played to change the state.
- */
public void setDimmed(boolean dimmed, boolean fade) {
if (mDimmed != dimmed) {
mDimmed = dimmed;
@@ -226,7 +223,7 @@
}
int startAlpha = mDimmed ? 255 : 0;
int endAlpha = mDimmed ? 0 : 255;
- int duration = NotificationActivator.ANIMATION_LENGTH_MS;
+ int duration = BACKGROUND_ANIMATION_LENGTH_MS;
// Check whether there is already a background animation running.
if (mBackgroundAnimator != null) {
startAlpha = (Integer) mBackgroundAnimator.getAnimatedValue();
@@ -313,8 +310,8 @@
}
@Override
- public void setActualHeight(int actualHeight) {
- super.setActualHeight(actualHeight);
+ public void setActualHeight(int actualHeight, boolean notifyListeners) {
+ super.setActualHeight(actualHeight, notifyListeners);
invalidate();
setPivotY(actualHeight / 2);
}
@@ -331,6 +328,6 @@
public interface OnActivatedListener {
void onActivated(View view);
- void onReset(View view);
+ void onActivationReset(View view);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 2c7464a..ecefc39 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -70,7 +70,7 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIconList;
-import com.android.internal.util.LegacyNotificationUtil;
+import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.SearchPanelView;
@@ -143,7 +143,7 @@
// public mode, private notifications, etc
private boolean mLockscreenPublicMode = false;
private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
- private LegacyNotificationUtil mLegacyNotificationUtil = LegacyNotificationUtil.getInstance();
+ private NotificationColorUtil mNotificationColorUtil = NotificationColorUtil.getInstance();
private UserManager mUserManager;
@@ -302,7 +302,7 @@
ArrayList<StatusBarNotification> notifications = new ArrayList<StatusBarNotification>();
mCommandQueue = new CommandQueue(this, iconList);
- int[] switches = new int[7];
+ int[] switches = new int[8];
ArrayList<IBinder> binders = new ArrayList<IBinder>();
try {
mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications,
@@ -317,7 +317,7 @@
setSystemUiVisibility(switches[1], 0xffffffff);
topAppWindowChanged(switches[2] != 0);
// StatusBarManagerService has a back up of IME token and it's restored here.
- setImeWindowStatus(binders.get(0), switches[3], switches[4]);
+ setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[7] != 0);
setHardKeyboardStatus(switches[5] != 0, switches[6] != 0);
// Set up the initial icon state
@@ -852,7 +852,7 @@
Drawable iconDrawable = StatusBarIconView.getIcon(mContext, ic);
icon.setImageDrawable(iconDrawable);
- if (mLegacyNotificationUtil.isGrayscale(iconDrawable)) {
+ if (mNotificationColorUtil.isGrayscale(iconDrawable)) {
icon.setBackgroundResource(
com.android.internal.R.drawable.notification_icon_legacy_bg_inset);
}
@@ -1067,7 +1067,6 @@
entry.row.setSystemExpanded(top);
}
}
- entry.row.setDimmed(onKeyguard, false /* fade */);
boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
if (onKeyguard && (visibleNotifications >= maxKeyguardNotifications
|| !showOnKeyguard)) {
@@ -1087,48 +1086,11 @@
if (onKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) {
mKeyguardIconOverflowContainer.setVisibility(View.VISIBLE);
- mKeyguardIconOverflowContainer.setDimmed(true /* dimmed */, false /* fade */);
} else {
mKeyguardIconOverflowContainer.setVisibility(View.GONE);
}
}
- @Override
- public void onActivated(View view) {
- int n = mNotificationData.size();
- for (int i = 0; i < n; i++) {
- NotificationData.Entry entry = mNotificationData.get(i);
- if (entry.row.getVisibility() != View.GONE) {
- if (view == entry.row) {
- entry.row.getActivator().activate();
- } else {
- entry.row.getActivator().activateInverse();
- }
- }
- }
- if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) {
- if (view == mKeyguardIconOverflowContainer) {
- mKeyguardIconOverflowContainer.getActivator().activate();
- } else {
- mKeyguardIconOverflowContainer.getActivator().activateInverse();
- }
- }
- }
-
- @Override
- public void onReset(View view) {
- int n = mNotificationData.size();
- for (int i = 0; i < n; i++) {
- NotificationData.Entry entry = mNotificationData.get(i);
- if (entry.row.getVisibility() != View.GONE) {
- entry.row.getActivator().reset();
- }
- }
- if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) {
- mKeyguardIconOverflowContainer.getActivator().reset();
- }
- }
-
private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
return sbn.getNotification().priority >= Notification.PRIORITY_LOW;
}
@@ -1144,7 +1106,6 @@
protected abstract void updateNotificationIcons();
protected abstract void tick(IBinder key, StatusBarNotification n, boolean firstTime);
protected abstract void updateExpandedViewPos(int expandedPosition);
- protected abstract int getExpandedViewMaxHeight();
protected abstract boolean shouldDisableNavbarGestures();
protected boolean isTopNotification(ViewGroup parent, NotificationData.Entry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index bbbe8fa..5362af5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -65,6 +65,8 @@
public static final int FLAG_EXCLUDE_INPUT_METHODS_PANEL = 1 << 3;
public static final int FLAG_EXCLUDE_COMPAT_MODE_PANEL = 1 << 4;
+ private static final String SHOW_IME_SWITCHER_KEY = "showImeSwitcherKey";
+
private StatusBarIconList mList;
private Callbacks mCallbacks;
private Handler mHandler = new H();
@@ -91,7 +93,8 @@
public void animateExpandSettingsPanel();
public void setSystemUiVisibility(int vis, int mask);
public void topAppWindowChanged(boolean visible);
- public void setImeWindowStatus(IBinder token, int vis, int backDisposition);
+ public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher);
public void setHardKeyboardStatus(boolean available, boolean enabled);
public void toggleRecentApps();
public void preloadRecentApps();
@@ -190,11 +193,13 @@
}
}
- public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
+ public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher) {
synchronized (mList) {
mHandler.removeMessages(MSG_SHOW_IME_BUTTON);
- mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, vis, backDisposition, token)
- .sendToTarget();
+ Message m = mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, vis, backDisposition, token);
+ m.getData().putBoolean(SHOW_IME_SWITCHER_KEY, showImeSwitcher);
+ m.sendToTarget();
}
}
@@ -298,7 +303,8 @@
mCallbacks.topAppWindowChanged(msg.arg1 != 0);
break;
case MSG_SHOW_IME_BUTTON:
- mCallbacks.setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2);
+ mCallbacks.setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2,
+ msg.getData().getBoolean(SHOW_IME_SWITCHER_KEY, false));
break;
case MSG_SET_HARD_KEYBOARD_STATUS:
mCallbacks.setHardKeyboardStatus(msg.arg1 != 0, msg.arg2 != 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index e471754..5b2ea0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -117,7 +117,7 @@
} else {
if (mDraggedFarEnough) {
mDraggedFarEnough = false;
- mOnDragDownListener.onReset();
+ mOnDragDownListener.onDragDownReset();
}
}
return true;
@@ -188,7 +188,7 @@
cancelExpansion(mStartingChild);
}
mDraggingDown = false;
- mOnDragDownListener.onReset();
+ mOnDragDownListener.onDragDownReset();
}
private ExpandableView findView(float x, float y) {
@@ -200,7 +200,7 @@
public interface OnDragDownListener {
void onDraggedDown(View startingChild);
- void onReset();
+ void onDragDownReset();
void onThresholdReached();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index e5512a3..39f2bb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -52,7 +52,6 @@
private NotificationContentView mPublicLayout;
private NotificationContentView mPrivateLayout;
private int mMaxExpandHeight;
- private NotificationActivator mActivator;
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -63,8 +62,6 @@
super.onFinishInflate();
mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
-
- mActivator = new NotificationActivator(this, this);
}
@Override
@@ -208,23 +205,10 @@
mPrivateLayout.setVisibility(show ? View.GONE : View.VISIBLE);
}
- /**
- * Sets the notification as dimmed, meaning that it will appear in a more gray variant.
- */
- @Override
- public void setDimmed(boolean dimmed, boolean fade) {
- super.setDimmed(dimmed, fade);
- mActivator.setDimmed(dimmed, fade);
- }
-
public int getMaxExpandHeight() {
return mMaxExpandHeight;
}
- public NotificationActivator getActivator() {
- return mActivator;
- }
-
/**
* @return the potential height this view could expand in addition.
*/
@@ -238,10 +222,10 @@
}
@Override
- public void setActualHeight(int height) {
- mPrivateLayout.setActualHeight(height);
+ public void setActualHeight(int height, boolean notifyListeners) {
+ mPrivateLayout.setActualHeight(height, notifyListeners);
invalidate();
- super.setActualHeight(height);
+ super.setActualHeight(height, notifyListeners);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index 43eb5b5..a42c194 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -33,8 +33,8 @@
}
@Override
- public void setActualHeight(int actualHeight) {
- super.setActualHeight(actualHeight);
+ public void setActualHeight(int actualHeight, boolean notifyListeners) {
+ super.setActualHeight(actualHeight, notifyListeners);
updateOutline();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 33e9051..281bd2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -17,11 +17,6 @@
package com.android.systemui.statusbar;
import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Outline;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@@ -66,10 +61,19 @@
/**
* Sets the actual height of this notification. This is different than the laid out
* {@link View#getHeight()}, as we want to avoid layouting during scrolling and expanding.
+ *
+ * @param actualHeight The height of this notification.
+ * @param notifyListeners Whether the listener should be informed about the change.
*/
- public void setActualHeight(int actualHeight) {
+ public void setActualHeight(int actualHeight, boolean notifyListeners) {
mActualHeight = actualHeight;
- notifyHeightChanged();
+ if (notifyListeners) {
+ notifyHeightChanged();
+ }
+ }
+
+ public void setActualHeight(int actualHeight) {
+ setActualHeight(actualHeight, true);
}
/**
@@ -96,6 +100,15 @@
}
/**
+ * Sets the notification as dimmed. The default implementation does nothing.
+ *
+ * @param dimmed Whether the notification should be dimmed.
+ * @param fade Whether an animation should be played to change the state.
+ */
+ public void setDimmed(boolean dimmed, boolean fade) {
+ }
+
+ /**
* @return The desired notification height.
*/
public int getIntrinsicHeight() {
@@ -112,6 +125,10 @@
mClipTopAmount = clipTopAmount;
}
+ public int getClipTopAmount() {
+ return mClipTopAmount;
+ }
+
public void setOnHeightChangedListener(OnHeightChangedListener listener) {
mOnHeightChangedListener = listener;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java
deleted file mode 100644
index a03aeec..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar;
-
-import android.content.Context;
-import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-import com.android.systemui.R;
-
-/**
- * A helper class used by both {@link com.android.systemui.statusbar.ExpandableNotificationRow} and
- * {@link com.android.systemui.statusbar.NotificationOverflowIconsView} to make a notification look
- * active after tapping it once on the Keyguard.
- */
-public class NotificationActivator {
-
- public static final int ANIMATION_LENGTH_MS = 220;
- private static final float INVERSE_ALPHA = 0.9f;
- private static final float DIMMED_SCALE = 0.95f;
-
- /**
- * Normal state. Notification is fully interactable.
- */
- private static final int STATE_NORMAL = 0;
-
- /**
- * Dimmed state. Neutral state when on the lockscreen, with slight transparency and scaled down
- * a bit.
- */
- private static final int STATE_DIMMED = 1;
-
- /**
- * Activated state. Used after tapping a notification on the lockscreen. Normal transparency and
- * normal scale.
- */
- private static final int STATE_ACTIVATED = 2;
-
- /**
- * Inverse activated state. Used for the other notifications on the lockscreen when tapping on
- * one.
- */
- private static final int STATE_ACTIVATED_INVERSE = 3;
-
- private final View mTargetView;
- private final View mHotspotView;
- private final Interpolator mFastOutSlowInInterpolator;
- private final Interpolator mLinearOutSlowInInterpolator;
- private final int mTranslationZ;
-
- private int mState;
-
- public NotificationActivator(View targetView, View hotspotView) {
- mTargetView = targetView;
- mHotspotView = hotspotView;
- Context ctx = targetView.getContext();
- mFastOutSlowInInterpolator =
- AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_slow_in);
- mLinearOutSlowInInterpolator =
- AnimationUtils.loadInterpolator(ctx, android.R.interpolator.linear_out_slow_in);
- mTranslationZ =
- ctx.getResources().getDimensionPixelSize(R.dimen.z_distance_between_notifications);
- mTargetView.animate().setDuration(ANIMATION_LENGTH_MS);
- }
-
- public void activateInverse() {
- if (mState == STATE_ACTIVATED_INVERSE) {
- return;
- }
- mTargetView.animate().cancel();
- mTargetView.animate().withLayer().alpha(INVERSE_ALPHA);
- mState = STATE_ACTIVATED_INVERSE;
- }
-
- public void addHotspot() {
- mHotspotView.getBackground().setHotspot(
- 0, mHotspotView.getWidth()/2, mHotspotView.getHeight()/2);
- }
-
- public void activate() {
- if (mState == STATE_ACTIVATED) {
- return;
- }
- mTargetView.animate().cancel();
- mTargetView.animate()
- .setInterpolator(mLinearOutSlowInInterpolator)
- .scaleX(1)
- .scaleY(1)
- .translationZBy(mTranslationZ);
- mState = STATE_ACTIVATED;
- }
-
- public void reset() {
- if (mState == STATE_DIMMED) {
- return;
- }
- mTargetView.animate().cancel();
- mTargetView.animate()
- .setInterpolator(mFastOutSlowInInterpolator)
- .scaleX(DIMMED_SCALE)
- .scaleY(DIMMED_SCALE)
- .translationZBy(-mTranslationZ);
- if (mTargetView.getAlpha() != 1.0f) {
- mTargetView.animate().withLayer().alpha(1);
- }
- mState = STATE_DIMMED;
- }
-
- public void setDimmed(boolean dimmed, boolean fade) {
- if (dimmed) {
- mTargetView.animate().cancel();
- if (fade) {
- mTargetView.animate()
- .setInterpolator(mFastOutSlowInInterpolator)
- .scaleX(DIMMED_SCALE)
- .scaleY(DIMMED_SCALE);
- } else {
- mTargetView.setScaleX(DIMMED_SCALE);
- mTargetView.setScaleY(DIMMED_SCALE);
- }
- mState = STATE_DIMMED;
- } else {
- mTargetView.animate().cancel();
- if (fade) {
- mTargetView.animate()
- .setInterpolator(mFastOutSlowInInterpolator)
- .scaleX(1)
- .scaleY(1);
- } else {
- mTargetView.animate().cancel();
- mTargetView.setScaleX(1);
- mTargetView.setScaleY(1);
- }
- mState = STATE_NORMAL;
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 1f15eaf..9df2701 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -70,8 +70,8 @@
}
@Override
- public void setActualHeight(int actualHeight) {
- super.setActualHeight(actualHeight);
+ public void setActualHeight(int actualHeight, boolean notifyListeners) {
+ super.setActualHeight(actualHeight, notifyListeners);
selectLayout();
updateClipping();
}
@@ -94,10 +94,6 @@
updateClipping();
}
- public int getClipTopAmount() {
- return mClipTopAmount;
- }
-
private void updateClipping() {
mClipBounds.set(0, mClipTopAmount, getWidth(), mActualHeight);
setClipBounds(mClipBounds);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
index e6b5600..864c597 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
@@ -28,14 +28,13 @@
public class NotificationOverflowContainer extends ActivatableNotificationView {
private NotificationOverflowIconsView mIconsView;
- private NotificationActivator mActivator;
public NotificationOverflowContainer(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
- public void setActualHeight(int currentHeight) {
+ public void setActualHeight(int currentHeight, boolean notifyListeners) {
// noop
}
@@ -54,22 +53,9 @@
super.onFinishInflate();
mIconsView = (NotificationOverflowIconsView) findViewById(R.id.overflow_icons_view);
mIconsView.setMoreText((TextView) findViewById(R.id.more_text));
-
- mActivator = new NotificationActivator(this, this);
- setDimmed(true, false);
- }
-
- @Override
- public void setDimmed(boolean dimmed, boolean fade) {
- super.setDimmed(dimmed, fade);
- mActivator.setDimmed(dimmed, fade);
}
public NotificationOverflowIconsView getIconsView() {
return mIconsView;
}
-
- public NotificationActivator getActivator() {
- return mActivator;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 627b80f..f63ba9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -16,11 +16,17 @@
package com.android.systemui.statusbar.phone;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
+import android.view.VelocityTracker;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableView;
@@ -29,18 +35,40 @@
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
public class NotificationPanelView extends PanelView implements
- ExpandableView.OnHeightChangedListener {
+ ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
+ View.OnClickListener {
public static final boolean DEBUG_GESTURES = true;
+ private static final int EXPANSION_ANIMATION_LENGTH = 375;
PhoneStatusBar mStatusBar;
- private View mHeader;
+ private StatusBarHeaderView mHeader;
+ private QuickSettingsContainerView mQsContainer;
private View mKeyguardStatusView;
+ private ObservableScrollView mScrollView;
+ private View mStackScrollerContainer;
private NotificationStackScrollLayout mNotificationStackScroller;
- private boolean mTrackingSettings;
private int mNotificationTopPadding;
private boolean mAnimateNextTopPaddingChange;
+ private Interpolator mExpansionInterpolator;
+
+ private int mTrackingPointer;
+ private VelocityTracker mVelocityTracker;
+ private boolean mTracking;
+ private boolean mQsExpanded;
+ private float mInitialHeightOnTouch;
+ private float mInitialTouchX;
+ private float mInitialTouchY;
+ private float mQsExpansionHeight;
+ private int mQsMinExpansionHeight;
+ private int mQsMaxExpansionHeight;
+ private int mMinStackHeight;
+ private float mNotificationTranslation;
+ private int mStackScrollerIntrinsicPadding;
+ private boolean mQsExpansionEnabled = true;
+ private ValueAnimator mQsExpansionAnimator;
+
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -63,14 +91,21 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
-
- mHeader = findViewById(R.id.header);
+ mHeader = (StatusBarHeaderView) findViewById(R.id.header);
+ mHeader.getBackgroundView().setOnClickListener(this);
mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
+ mStackScrollerContainer = findViewById(R.id.notification_container_parent);
+ mQsContainer = (QuickSettingsContainerView) findViewById(R.id.quick_settings_container);
+ mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
+ mScrollView.setListener(this);
mNotificationStackScroller = (NotificationStackScrollLayout)
findViewById(R.id.notification_stack_scroller);
mNotificationStackScroller.setOnHeightChangedListener(this);
mNotificationTopPadding = getResources().getDimensionPixelSize(
R.dimen.notifications_top_padding);
+ mMinStackHeight = getResources().getDimensionPixelSize(R.dimen.collapsed_stack_height);
+ mExpansionInterpolator = AnimationUtils.loadInterpolator(
+ getContext(), android.R.interpolator.fast_out_slow_in);
}
@Override
@@ -78,11 +113,21 @@
super.onLayout(changed, left, top, right, bottom);
int keyguardBottomMargin =
((MarginLayoutParams) mKeyguardStatusView.getLayoutParams()).bottomMargin;
- mNotificationStackScroller.setTopPadding(mStatusBar.getBarState() == StatusBarState.KEYGUARD
- ? mKeyguardStatusView.getBottom() + keyguardBottomMargin
- : mHeader.getBottom() + mNotificationTopPadding,
- mAnimateNextTopPaddingChange);
- mAnimateNextTopPaddingChange = false;
+ if (!mQsExpanded) {
+ mStackScrollerIntrinsicPadding = mStatusBar.getBarState() == StatusBarState.KEYGUARD
+ ? mKeyguardStatusView.getBottom() + keyguardBottomMargin
+ : mHeader.getBottom() + mNotificationTopPadding;
+ mNotificationStackScroller.setTopPadding(mStackScrollerIntrinsicPadding,
+ mAnimateNextTopPaddingChange);
+ mAnimateNextTopPaddingChange = false;
+ }
+
+ // Calculate quick setting heights.
+ mQsMinExpansionHeight = mHeader.getCollapsedHeight();
+ mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getHeight();
+ if (mQsExpansionHeight == 0) {
+ mQsExpansionHeight = mQsMinExpansionHeight;
+ }
}
public void animateNextTopPaddingChange() {
@@ -90,6 +135,30 @@
requestLayout();
}
+ /**
+ * @return Whether Quick Settings are currently expanded.
+ */
+ public boolean isQsExpanded() {
+ return mQsExpanded;
+ }
+
+ public void setQsExpansionEnabled(boolean qsExpansionEnabled) {
+ mQsExpansionEnabled = qsExpansionEnabled;
+ mHeader.setExpansionEnabled(qsExpansionEnabled);
+ }
+
+ public void closeQs() {
+ cancelAnimation();
+ setQsExpansion(mQsMinExpansionHeight);
+ }
+
+ public void openQs() {
+ cancelAnimation();
+ if (mQsExpansionEnabled) {
+ setQsExpansion(mQsMaxExpansionHeight);
+ }
+ }
+
@Override
public void fling(float vel, boolean always) {
GestureRecorder gr = ((PhoneStatusBarView) mBar).mBar.getGestureRecorder();
@@ -114,42 +183,245 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- // intercept for quick settings
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- final View target = mStatusBar.getBarState() == StatusBarState.KEYGUARD
- ? mKeyguardStatusView
- : mHeader;
- final boolean inTarget = PhoneStatusBar.inBounds(target, event, true);
- if (inTarget && !isInSettings()) {
- mTrackingSettings = true;
- requestDisallowInterceptTouchEvent(true);
- return true;
- }
- if (!inTarget && isInSettings()) {
- mTrackingSettings = true;
- requestDisallowInterceptTouchEvent(true);
- return true;
- }
+ int pointerIndex = event.findPointerIndex(mTrackingPointer);
+ if (pointerIndex < 0) {
+ pointerIndex = 0;
+ mTrackingPointer = event.getPointerId(pointerIndex);
}
- return super.onInterceptTouchEvent(event);
+ final float x = event.getX(pointerIndex);
+ final float y = event.getY(pointerIndex);
+
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ mInitialTouchY = y;
+ mInitialTouchX = x;
+ initVelocityTracker();
+ trackMovement(event);
+ if (shouldIntercept(mInitialTouchX, mInitialTouchY, 0)) {
+ getParent().requestDisallowInterceptTouchEvent(true);
+ }
+ break;
+ case MotionEvent.ACTION_POINTER_UP:
+ final int upPointer = event.getPointerId(event.getActionIndex());
+ if (mTrackingPointer == upPointer) {
+ // gesture is ongoing, find a new pointer to track
+ final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+ mTrackingPointer = event.getPointerId(newIndex);
+ mInitialTouchX = event.getX(newIndex);
+ mInitialTouchY = event.getY(newIndex);
+ }
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ final float h = y - mInitialTouchY;
+ trackMovement(event);
+ if (Math.abs(h) > mTouchSlop && Math.abs(h) > Math.abs(x - mInitialTouchX)
+ && shouldIntercept(mInitialTouchX, mInitialTouchY, h)) {
+ onQsExpansionStarted();
+ mInitialHeightOnTouch = mQsExpansionHeight;
+ mInitialTouchY = y;
+ mInitialTouchX = x;
+ mTracking = true;
+ return true;
+ }
+ break;
+ }
+ return !mQsExpanded && super.onInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO: Handle doublefinger swipe to notifications again. Look at history for a reference
// implementation.
- if (mTrackingSettings) {
- mStatusBar.onSettingsEvent(event);
- if (event.getAction() == MotionEvent.ACTION_UP
- || event.getAction() == MotionEvent.ACTION_CANCEL) {
- mTrackingSettings = false;
+ if (mTracking) {
+ int pointerIndex = event.findPointerIndex(mTrackingPointer);
+ if (pointerIndex < 0) {
+ pointerIndex = 0;
+ mTrackingPointer = event.getPointerId(pointerIndex);
+ }
+ final float y = event.getY(pointerIndex);
+ final float x = event.getX(pointerIndex);
+
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ mTracking = true;
+ mInitialTouchY = y;
+ mInitialTouchX = x;
+ onQsExpansionStarted();
+ mInitialHeightOnTouch = mQsExpansionHeight;
+ initVelocityTracker();
+ trackMovement(event);
+ break;
+
+ case MotionEvent.ACTION_POINTER_UP:
+ final int upPointer = event.getPointerId(event.getActionIndex());
+ if (mTrackingPointer == upPointer) {
+ // gesture is ongoing, find a new pointer to track
+ final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+ final float newY = event.getY(newIndex);
+ final float newX = event.getX(newIndex);
+ mTrackingPointer = event.getPointerId(newIndex);
+ mInitialHeightOnTouch = mQsExpansionHeight;
+ mInitialTouchY = newY;
+ mInitialTouchX = newX;
+ }
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ final float h = y - mInitialTouchY;
+ setQsExpansion(h + mInitialHeightOnTouch);
+ trackMovement(event);
+ break;
+
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mTracking = false;
+ mTrackingPointer = -1;
+ trackMovement(event);
+
+ float vel = getCurrentVelocity();
+
+ // TODO: Better logic whether we should expand or not.
+ flingSettings(vel, vel > 0);
+
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ break;
}
return true;
}
- if (isInSettings()) {
- return true;
+
+ // Consume touch events when QS are expanded.
+ return mQsExpanded || super.onTouchEvent(event);
+ }
+
+ private void onQsExpansionStarted() {
+ cancelAnimation();
+
+ // Reset scroll position and apply that position to the expanded height.
+ float height = mQsExpansionHeight - mScrollView.getScrollY();
+ mScrollView.scrollTo(0, 0);
+ setQsExpansion(height);
+ }
+
+ private void expandQs() {
+ mHeader.setExpanded(true);
+ mNotificationStackScroller.setEnabled(false);
+ mScrollView.setVisibility(View.VISIBLE);
+ mQsExpanded = true;
+ }
+
+ private void collapseQs() {
+ mHeader.setExpanded(false);
+ mNotificationStackScroller.setEnabled(true);
+ mScrollView.setVisibility(View.INVISIBLE);
+ mQsExpanded = false;
+ }
+
+ private void setQsExpansion(float height) {
+ height = Math.min(Math.max(height, mQsMinExpansionHeight), mQsMaxExpansionHeight);
+ if (height > mQsMinExpansionHeight && !mQsExpanded) {
+ expandQs();
+ } else if (height <= mQsMinExpansionHeight && mQsExpanded) {
+ collapseQs();
}
- return super.onTouchEvent(event);
+ mQsExpansionHeight = height;
+ mHeader.setExpansion(height);
+ setQsTranslation(height);
+ setQsStackScrollerPadding(height);
+ }
+
+ private void setQsTranslation(float height) {
+ mQsContainer.setY(height - mQsContainer.getHeight());
+ }
+
+ private void setQsStackScrollerPadding(float height) {
+ float start = height - mScrollView.getScrollY() + mNotificationTopPadding;
+ float stackHeight = mNotificationStackScroller.getHeight() - start;
+ if (stackHeight <= mMinStackHeight) {
+ float overflow = mMinStackHeight - stackHeight;
+ stackHeight = mMinStackHeight;
+ start = mNotificationStackScroller.getHeight() - stackHeight;
+ mNotificationStackScroller.setTranslationY(overflow);
+ mNotificationTranslation = overflow + mScrollView.getScrollY();
+ } else {
+ mNotificationStackScroller.setTranslationY(0);
+ mNotificationTranslation = mScrollView.getScrollY();
+ }
+ mNotificationStackScroller.setTopPadding(clampQsStackScrollerPadding((int) start), false);
+ }
+
+ private int clampQsStackScrollerPadding(int desiredPadding) {
+ return Math.max(desiredPadding, mStackScrollerIntrinsicPadding);
+ }
+
+ private void trackMovement(MotionEvent event) {
+ if (mVelocityTracker != null) mVelocityTracker.addMovement(event);
+ }
+
+ private void initVelocityTracker() {
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ }
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+
+ private float getCurrentVelocity() {
+ if (mVelocityTracker == null) {
+ return 0;
+ }
+ mVelocityTracker.computeCurrentVelocity(1000);
+ return mVelocityTracker.getYVelocity();
+ }
+
+ private void cancelAnimation() {
+ if (mQsExpansionAnimator != null) {
+ mQsExpansionAnimator.cancel();
+ }
+ }
+ private void flingSettings(float vel, boolean expand) {
+
+ // TODO: Actually use velocity.
+
+ float target = expand ? mQsMaxExpansionHeight : mQsMinExpansionHeight;
+ ValueAnimator animator = ValueAnimator.ofFloat(mQsExpansionHeight, target);
+ animator.setDuration(EXPANSION_ANIMATION_LENGTH);
+ animator.setInterpolator(mExpansionInterpolator);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ setQsExpansion((Float) animation.getAnimatedValue());
+ }
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mQsExpansionAnimator = null;
+ }
+ });
+ animator.start();
+ mQsExpansionAnimator = animator;
+ }
+
+ /**
+ * @return Whether we should intercept a gesture to open Quick Settings.
+ */
+ private boolean shouldIntercept(float x, float y, float yDiff) {
+ if (!mQsExpansionEnabled) {
+ return false;
+ }
+ View headerView = mStatusBar.getBarState() == StatusBarState.KEYGUARD && !mQsExpanded
+ ? mKeyguardStatusView
+ : mHeader;
+ boolean onHeader = x >= headerView.getLeft() && x <= headerView.getRight()
+ && y >= headerView.getTop() && y <= headerView.getBottom();
+ if (mQsExpanded) {
+ return onHeader || (mScrollView.isScrolledToBottom() && yDiff < 0);
+ } else {
+ return onHeader;
+ }
}
@Override
@@ -164,14 +436,16 @@
protected int getMaxPanelHeight() {
if (!isInSettings()) {
int maxPanelHeight = super.getMaxPanelHeight();
- int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin();
+ int notificationMarginBottom = mStackScrollerContainer.getPaddingBottom();
+ int emptyBottomMargin = notificationMarginBottom
+ + mNotificationStackScroller.getEmptyBottomMargin();
return maxPanelHeight - emptyBottomMargin;
}
return super.getMaxPanelHeight();
}
private boolean isInSettings() {
- return mStatusBar != null && mStatusBar.isFlippedToSettings();
+ return mQsExpanded;
}
@Override
@@ -200,4 +474,24 @@
public void onHeightChanged(ExpandableView view) {
requestPanelHeightUpdate();
}
+
+ @Override
+ public void onScrollChanged() {
+ if (mQsExpanded) {
+ mNotificationStackScroller.setTranslationY(
+ mNotificationTranslation - mScrollView.getScrollY());
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == mHeader.getBackgroundView()) {
+ onQsExpansionStarted();
+ if (mQsExpanded) {
+ flingSettings(0 /* vel */, false /* expand */);
+ } else if (mQsExpansionEnabled) {
+ flingSettings(0 /* vel */, true /* expand */);
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
new file mode 100644
index 0000000..f41e78d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+/**
+ * The container with notification stack scroller and quick settings inside.
+ */
+public class NotificationsQuickSettingsContainer extends FrameLayout {
+
+ public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected boolean fitSystemWindows(Rect insets) {
+ setPadding(0, 0, 0, insets.bottom);
+ insets.bottom = 0;
+ return true;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java
new file mode 100644
index 0000000..46484f3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ScrollView;
+
+/**
+ * A scroll view which can be observed for scroll change events.
+ */
+public class ObservableScrollView extends ScrollView {
+
+ private Listener mListener;
+
+ public ObservableScrollView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public void setListener(Listener listener) {
+ mListener = listener;
+ }
+
+ public boolean isScrolledToBottom() {
+ return getScrollY() == getMaxScrollY();
+ }
+
+ private int getMaxScrollY() {
+ int scrollRange = 0;
+ if (getChildCount() > 0) {
+ View child = getChildAt(0);
+ scrollRange = Math.max(0,
+ child.getHeight() - (getHeight() - mPaddingBottom - mPaddingTop));
+ }
+ return scrollRange;
+ }
+
+ @Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ super.onScrollChanged(l, t, oldl, oldt);
+ if (mListener != null) {
+ mListener.onScrollChanged();
+ }
+ }
+
+ public interface Listener {
+ void onScrollChanged();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 0cdca66..8c70517 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -75,7 +75,7 @@
private boolean mClosing;
private boolean mTracking;
private int mTrackingPointer;
- private int mTouchSlop;
+ protected int mTouchSlop;
private TimeAnimator mTimeAnimator;
private ObjectAnimator mPeekAnimator;
@@ -220,9 +220,9 @@
private float mVel, mAccel;
protected int mMaxPanelHeight = 0;
private String mViewName;
- protected float mInitialTouchY;
- protected float mInitialTouchX;
- protected float mFinalTouchY;
+ private float mInitialTouchY;
+ private float mInitialTouchX;
+ private float mFinalTouchY;
protected void onExpandingFinished() {
}
@@ -526,11 +526,14 @@
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
+ if (mTimeAnimator.isRunning()) {
+ mTimeAnimator.cancel(); // end any outstanding animations
+ return true;
+ }
mInitialTouchY = y;
mInitialTouchX = x;
initVelocityTracker();
trackMovement(event);
- mTimeAnimator.cancel(); // end any outstanding animations
break;
case MotionEvent.ACTION_POINTER_UP:
final int upPointer = event.getPointerId(event.getActionIndex());
@@ -569,7 +572,7 @@
}
protected boolean isScrolledToBottom() {
- return false;
+ return true;
}
protected float getContentHeight() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index f945c79..92eee4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -73,7 +73,6 @@
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewPropertyAnimator;
@@ -192,8 +191,6 @@
int mIconHPadding = -1;
Display mDisplay;
Point mCurrentDisplaySize = new Point();
- private float mHeadsUpVerticalOffset;
- private int[] mStackScrollerPosition = new int[2];
StatusBarWindowView mStatusBarWindow;
PhoneStatusBarView mStatusBarView;
@@ -222,14 +219,13 @@
NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
View mExpandedContents;
int mNotificationPanelGravity;
- int mNotificationPanelMarginBottomPx, mNotificationPanelMarginPx;
+ int mNotificationPanelMarginBottomPx;
float mNotificationPanelMinHeightFrac;
boolean mNotificationPanelIsFullScreenWidth;
TextView mNotificationPanelDebugText;
// settings
QuickSettings mQS;
- boolean mHasQuickSettings;
View mFlipSettingsView;
QuickSettingsContainerView mSettingsContainer;
@@ -245,14 +241,14 @@
int mKeyguardMaxNotificationCount;
View mDateTimeView;
View mClearButton;
- FlipperButton mHeaderFlipper, mKeyguardFlipper;
+ ImageView mHeaderFlipper;
// carrier/wifi label
private TextView mCarrierLabel;
private boolean mCarrierLabelVisible = false;
private int mCarrierLabelHeight;
private TextView mEmergencyCallLabel;
- private int mNotificationHeaderHeight;
+ private int mStatusBarHeaderHeight;
private View mKeyguardCarrierLabel;
private boolean mShowCarrierInPanel = false;
@@ -326,11 +322,12 @@
if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " +
"selfChange=%s userSetup=%s mUserSetup=%s",
selfChange, userSetup, mUserSetup));
- mHeaderFlipper.userSetup(userSetup);
- mKeyguardFlipper.userSetup(userSetup);
if (userSetup != mUserSetup) {
mUserSetup = userSetup;
+ if (mNotificationPanel != null) {
+ mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned() && userSetup);
+ }
if (!mUserSetup && mStatusBarView != null)
animateCollapseQuickSettings();
}
@@ -631,8 +628,7 @@
R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false);
mKeyguardIconOverflowContainer.setOnActivatedListener(this);
mKeyguardCarrierLabel = mStatusBarWindow.findViewById(R.id.keyguard_carrier_text);
- // TODO: Comment in when transition is ready.
- //mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
+ mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
mStackScroller.addView(mKeyguardIconOverflowContainer);
mExpandedContents = mStackScroller;
@@ -651,16 +647,13 @@
mClearButton.setEnabled(false);
mDateView = (DateView)mStatusBarWindow.findViewById(R.id.date);
- mHasQuickSettings = res.getBoolean(R.bool.config_hasQuickSettings);
-
mDateTimeView = mNotificationPanelHeader.findViewById(R.id.datetime);
if (mDateTimeView != null) {
mDateTimeView.setOnClickListener(mClockClickListener);
mDateTimeView.setEnabled(true);
}
- mHeaderFlipper = new FlipperButton(mStatusBarWindow.findViewById(R.id.header_flipper));
- mKeyguardFlipper =new FlipperButton(mStatusBarWindow.findViewById(R.id.keyguard_flipper));
+ mHeaderFlipper = (ImageView) mStatusBarWindow.findViewById(R.id.header_flipper);
if (!mNotificationPanelIsFullScreenWidth) {
mNotificationPanel.setSystemUiVisibility(
@@ -735,26 +728,23 @@
// updateCarrierLabelVisibility(false);
}
- // Quick Settings (where available, some restrictions apply)
- if (mHasQuickSettings) {
- // Quick Settings needs a container to survive
- mSettingsContainer = (QuickSettingsContainerView)
- mStatusBarWindow.findViewById(R.id.quick_settings_container);
- mFlipSettingsView = mSettingsContainer;
- if (mSettingsContainer != null) {
- mQS = new QuickSettings(mContext, mSettingsContainer);
- if (!mNotificationPanelIsFullScreenWidth) {
- mSettingsContainer.setSystemUiVisibility(
- View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS
- | View.STATUS_BAR_DISABLE_SYSTEM_INFO);
- }
- mQS.setService(this);
- mQS.setBar(mStatusBarView);
- mQS.setup(mNetworkController, mBluetoothController, mBatteryController,
- mLocationController, mRotationLockController);
- } else {
- mQS = null; // fly away, be free
+ // Quick Settings needs a container to survive
+ mSettingsContainer = (QuickSettingsContainerView)
+ mStatusBarWindow.findViewById(R.id.quick_settings_container);
+ mFlipSettingsView = mSettingsContainer;
+ if (mSettingsContainer != null) {
+ mQS = new QuickSettings(mContext, mSettingsContainer);
+ if (!mNotificationPanelIsFullScreenWidth) {
+ mSettingsContainer.setSystemUiVisibility(
+ View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS
+ | View.STATUS_BAR_DISABLE_SYSTEM_INFO);
}
+ mQS.setService(this);
+ mQS.setBar(mStatusBarView);
+ mQS.setup(mNetworkController, mBluetoothController, mBatteryController,
+ mLocationController, mRotationLockController);
+ } else {
+ mQS = null; // fly away, be free
}
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -775,101 +765,6 @@
return mStatusBarView;
}
- public boolean onSettingsEvent(MotionEvent event) {
- userActivity();
- if (mSettingsClosing
- && mFlipSettingsViewAnim != null && mFlipSettingsViewAnim.isRunning()) {
- return true;
- }
- if (mSettingsTracker != null) {
- mSettingsTracker.addMovement(event);
- }
- final int slop = ViewConfiguration.get(mContext).getScaledTouchSlop();
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- mSettingsTracker = VelocityTracker.obtain();
- mSettingsDownY = event.getY();
- mSettingsCancelled = false;
- mSettingsStarted = false;
- mSettingsClosing = mFlipSettingsView.getVisibility() == View.VISIBLE;
- if (mSettingsClosing) {
- mStackScroller.setVisibility(View.VISIBLE);
- } else {
- mFlipSettingsView.setTranslationY(-mNotificationPanel.getMeasuredHeight());
- }
- dispatchSettingsEvent(event);
- } else if (mSettingsTracker != null && (event.getAction() == MotionEvent.ACTION_UP
- || event.getAction() == MotionEvent.ACTION_CANCEL)) {
- final float dy = event.getY() - mSettingsDownY;
- final FlipperButton flipper = mState == StatusBarState.KEYGUARD
- ? mKeyguardFlipper
- : mHeaderFlipper;
- final boolean inButton = flipper.inHolderBounds(event);
- final boolean qsTap = mSettingsClosing && Math.abs(dy) < slop;
- if (!qsTap && !inButton) {
- mSettingsTracker.computeCurrentVelocity(1000);
- final float vy = mSettingsTracker.getYVelocity();
- final boolean animate = true;
- if (dy <= slop || vy <= 0) {
- flipToNotifications(animate);
- } else {
- flipToSettings(animate);
- }
- }
- mSettingsTracker.recycle();
- mSettingsTracker = null;
- dispatchSettingsEvent(event);
- } else if (mSettingsTracker != null && event.getAction() == MotionEvent.ACTION_MOVE) {
- final float dy = event.getY() - mSettingsDownY;
- if (mSettingsClosing) {
- positionSettings(dy);
- final boolean qsTap = Math.abs(dy) < slop;
- if (!mSettingsCancelled && !qsTap) {
- MotionEvent cancelEvent = MotionEvent.obtainNoHistory(event);
- cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
- dispatchSettingsEvent(cancelEvent);
- mSettingsCancelled = true;
- }
- } else {
- if (!mSettingsStarted && dy > slop) {
- mSettingsStarted = true;
- mFlipSettingsView.setVisibility(View.VISIBLE);
- mStackScroller.setVisibility(View.VISIBLE);
- }
- if (mSettingsStarted) {
- positionSettings(dy);
- }
- dispatchSettingsEvent(event);
- }
- }
- return true;
- }
-
- private void dispatchSettingsEvent(MotionEvent event) {
- final View target = mSettingsClosing ? mFlipSettingsView : mNotificationPanelHeader;
- final int[] targetLoc = new int[2];
- target.getLocationInWindow(targetLoc);
- final int[] panelLoc = new int[2];
- mNotificationPanel.getLocationInWindow(panelLoc);
- final int dx = targetLoc[0] - panelLoc[0];
- final int dy = targetLoc[1] - panelLoc[1];
- event.offsetLocation(-dx, -dy);
- target.dispatchTouchEvent(event);
- }
-
- private void positionSettings(float dy) {
- if (mSettingsClosing) {
- final int ph = mNotificationPanel.getMeasuredHeight();
- dy = Math.min(Math.max(-ph, dy), 0);
- mFlipSettingsView.setTranslationY(dy);
- mStackScroller.setTranslationY(ph + dy);
- } else {
- final int h = mFlipSettingsView.getBottom();
- dy = Math.min(Math.max(0, dy), h);
- mFlipSettingsView.setTranslationY(-h + dy);
- mStackScroller.setTranslationY(dy);
- }
- }
-
private void startKeyguard() {
KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
@@ -1230,8 +1125,11 @@
((ImageView)mClearButton).setImageResource(R.drawable.ic_notify_clear);
}
- mHeaderFlipper.refreshLayout();
- mKeyguardFlipper.refreshLayout();
+ if (mHeaderFlipper != null) {
+ // Force asset reloading
+ mHeaderFlipper.setImageDrawable(null);
+ mHeaderFlipper.setImageResource(R.drawable.ic_notify_quicksettings);
+ }
refreshAllStatusBarIcons();
}
@@ -1286,8 +1184,7 @@
}
}
- mHeaderFlipper.provisionCheck(provisioned);
- mKeyguardFlipper.provisionCheck(provisioned);
+ mNotificationPanel.setQsExpansionEnabled(provisioned && mUserSetup);
}
@Override
@@ -1362,7 +1259,7 @@
final boolean makeVisible =
!(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly())
&& mStackScroller.getHeight() < (mNotificationPanel.getHeight()
- - mCarrierLabelHeight - mNotificationHeaderHeight)
+ - mCarrierLabelHeight - mStatusBarHeaderHeight)
&& mStackScroller.getVisibility() == View.VISIBLE
&& mState != StatusBarState.KEYGUARD;
@@ -1775,47 +1672,8 @@
}
public void flipToNotifications(boolean animate) {
- cancelAnim(mFlipSettingsViewAnim);
- cancelAnim(mScrollViewAnim);
- cancelAnim(mClearButtonAnim);
- mHeaderFlipper.cancel();
- mKeyguardFlipper.cancel();
- mStackScroller.setVisibility(View.VISIBLE);
- final int h = mNotificationPanel.getMeasuredHeight();
- if (animate) {
- final float settingsY =
- mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : 0;
- final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : h;
- mScrollViewAnim = start(
- interpolator(mDecelerateInterpolator,
- ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, 0)
- .setDuration(FLIP_DURATION)
- ));
- mFlipSettingsViewAnim = start(
- setVisibilityWhenDone(
- interpolator(mDecelerateInterpolator,
- ObjectAnimator.ofFloat(
- mFlipSettingsView, View.TRANSLATION_Y, settingsY, -h))
- .setDuration(FLIP_DURATION),
- mFlipSettingsView, View.INVISIBLE));
- } else {
- mStackScroller.setTranslationY(0);
- mFlipSettingsView.setTranslationY(-h);
- mFlipSettingsView.setVisibility(View.INVISIBLE);
- }
- mHeaderFlipper.flipToNotifications(animate);
- mKeyguardFlipper.flipToNotifications(animate);
- mClearButton.setVisibility(View.VISIBLE);
- mClearButton.setAlpha(0f);
- setAreThereNotifications(); // this will show/hide the button as necessary
- mNotificationPanel.postDelayed(new Runnable() {
- public void run() {
- updateCarrierLabelVisibility(false);
- }
- }, animate ? FLIP_DURATION - 150 : 0);
- if (mOnFlipRunnable != null) {
- mOnFlipRunnable.run();
- }
+ // TODO: Animation
+ mNotificationPanel.closeQs();
}
@Override
@@ -1829,78 +1687,18 @@
if (!mUserSetup) return;
mNotificationPanel.expand();
- if (mFlipSettingsView.getVisibility() != View.VISIBLE
- || mFlipSettingsView.getTranslationY() < 0) {
- flipToSettings(true /*animate*/);
- }
+ mNotificationPanel.openQs();
if (false) postStartTracing();
}
public boolean isFlippedToSettings() {
- if (mFlipSettingsView != null) {
- return mFlipSettingsView.getVisibility() == View.VISIBLE;
+ if (mNotificationPanel != null) {
+ return mNotificationPanel.isQsExpanded();
}
return false;
}
- public void flipToSettings(boolean animate) {
- // Settings are not available in setup
- if (!mUserSetup) return;
-
- cancelAnim(mFlipSettingsViewAnim);
- cancelAnim(mScrollViewAnim);
- mHeaderFlipper.cancel();
- mKeyguardFlipper.cancel();
- cancelAnim(mClearButtonAnim);
-
- mFlipSettingsView.setVisibility(View.VISIBLE);
- final int h = mNotificationPanel.getMeasuredHeight();
- if (animate) {
- final float settingsY
- = mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : -h;
- final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : 0;
- mFlipSettingsViewAnim = start(
- startDelay(0,
- interpolator(mDecelerateInterpolator,
- ObjectAnimator.ofFloat(mFlipSettingsView, View.TRANSLATION_Y,
- settingsY, 0f)
- .setDuration(FLIP_DURATION)
- )));
- mScrollViewAnim = start(
- setVisibilityWhenDone(
- interpolator(mDecelerateInterpolator,
- ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, h)
- )
- .setDuration(FLIP_DURATION),
- mStackScroller, View.INVISIBLE));
- } else {
- mFlipSettingsView.setTranslationY(0);
- mStackScroller.setTranslationY(h);
- mStackScroller.setVisibility(View.INVISIBLE);
- }
- mHeaderFlipper.flipToSettings(animate);
- mKeyguardFlipper.flipToSettings(animate);
- if (animate) {
- mClearButtonAnim = start(
- setVisibilityWhenDone(
- ObjectAnimator.ofFloat(mClearButton, View.ALPHA, 0f)
- .setDuration(FLIP_DURATION),
- mClearButton, View.INVISIBLE));
- } else {
- mClearButton.setAlpha(0);
- mClearButton.setVisibility(View.INVISIBLE);
- }
- mNotificationPanel.postDelayed(new Runnable() {
- public void run() {
- updateCarrierLabelVisibility(false);
- }
- }, animate ? FLIP_DURATION - 150 : 0);
- if (mOnFlipRunnable != null) {
- mOnFlipRunnable.run();
- }
- }
-
public void animateCollapseQuickSettings() {
mStatusBarView.collapseAllPanels(true);
}
@@ -1927,12 +1725,10 @@
mStackScroller.setVisibility(View.VISIBLE);
mNotificationPanel.setVisibility(View.GONE);
- mFlipSettingsView.setVisibility(View.GONE);
setAreThereNotifications(); // show the clear button
- mHeaderFlipper.reset();
- mKeyguardFlipper.reset();
+ mNotificationPanel.closeQs();
mExpandedVisible = false;
if (mNavigationBarView != null)
@@ -2235,7 +2031,8 @@
}
@Override
- public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
+ public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher) {
boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
int flags = mNavigationIconHints;
if ((backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) || imeShown) {
@@ -2243,7 +2040,7 @@
} else {
flags &= ~NAVIGATION_HINT_BACK_ALT;
}
- if (imeShown) {
+ if (showImeSwitcher) {
flags |= NAVIGATION_HINT_IME_SHOWN;
} else {
flags &= ~NAVIGATION_HINT_IME_SHOWN;
@@ -2462,20 +2259,11 @@
}
}
- void updateExpandedInvisiblePosition() {
- mTrackingPosition = -mDisplayMetrics.heightPixels;
- }
-
static final float saturate(float a) {
return a < 0f ? 0f : (a > 1f ? 1f : a);
}
@Override
- protected int getExpandedViewMaxHeight() {
- return mDisplayMetrics.heightPixels - mNotificationPanelMarginBottomPx;
- }
-
- @Override
public void updateExpandedViewPos(int thingy) {
if (SPEW) Log.v(TAG, "updateExpandedViewPos");
@@ -2485,15 +2273,8 @@
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mNotificationPanel.getLayoutParams();
lp.gravity = mNotificationPanelGravity;
- lp.setMarginStart(mNotificationPanelMarginPx);
mNotificationPanel.setLayoutParams(lp);
- if (ENABLE_HEADS_UP && mHeadsUpNotificationView != null) {
- mHeadsUpNotificationView.setMargin(mNotificationPanelMarginPx);
- mStackScroller.getLocationOnScreen(mStackScrollerPosition);
- mHeadsUpVerticalOffset = mStackScrollerPosition[1] - mNaturalBarHeight;
- }
-
updateCarrierLabelVisibility(false);
}
@@ -2541,17 +2322,6 @@
animateCollapsePanels();
}
- private View.OnClickListener mSettingsButtonListener = new View.OnClickListener() {
- public void onClick(View v) {
- if (mHasQuickSettings) {
- animateExpandSettingsPanel();
- } else {
- startActivityDismissingKeyguard(
- new Intent(android.provider.Settings.ACTION_SETTINGS), true);
- }
- }
- };
-
private View.OnClickListener mClockClickListener = new View.OnClickListener() {
public void onClick(View v) {
startActivityDismissingKeyguard(
@@ -2652,17 +2422,6 @@
}
}
- public void animateHeadsUp(boolean animateInto, float frac) {
- if (!ENABLE_HEADS_UP || mHeadsUpNotificationView == null) return;
- frac = frac / 0.4f;
- frac = frac < 1.0f ? frac : 1.0f;
- float alpha = 1.0f - frac;
- float offset = mHeadsUpVerticalOffset * frac;
- offset = animateInto ? offset : 0f;
- mHeadsUpNotificationView.setAlpha(alpha);
- mHeadsUpNotificationView.setY(offset);
- }
-
public void onHeadsUpDismissed() {
if (mInterruptingNotificationEntry == null) return;
mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
@@ -2735,17 +2494,13 @@
mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity);
- mNotificationPanelMarginBottomPx
- = (int) res.getDimension(R.dimen.notification_panel_margin_bottom);
- mNotificationPanelMarginPx
- = (int) res.getDimension(R.dimen.notification_panel_margin_left);
mNotificationPanelGravity = res.getInteger(R.integer.notification_panel_layout_gravity);
if (mNotificationPanelGravity <= 0) {
mNotificationPanelGravity = Gravity.START | Gravity.TOP;
}
mCarrierLabelHeight = res.getDimensionPixelSize(R.dimen.carrier_label_height);
- mNotificationHeaderHeight = res.getDimensionPixelSize(R.dimen.notification_panel_header_height);
+ mStatusBarHeaderHeight = res.getDimensionPixelSize(R.dimen.status_bar_header_height);
mNotificationPanelMinHeightFrac = res.getFraction(R.dimen.notification_panel_min_height_frac, 1, 1);
if (mNotificationPanelMinHeightFrac < 0f || mNotificationPanelMinHeightFrac > 1f) {
@@ -3015,9 +2770,6 @@
private void updateKeyguardState() {
if (mState == StatusBarState.KEYGUARD) {
- if (isFlippedToSettings()) {
- flipToNotifications(false /*animate*/);
- }
mKeyguardStatusView.setVisibility(View.VISIBLE);
mKeyguardBottomArea.setVisibility(View.VISIBLE);
mKeyguardIndicationTextView.setVisibility(View.VISIBLE);
@@ -3025,7 +2777,7 @@
mKeyguardCarrierLabel.setVisibility(View.VISIBLE);
mNotificationPanelHeader.setVisibility(View.GONE);
- mKeyguardFlipper.setVisibility(View.VISIBLE);
+ mNotificationPanel.closeQs();
mSettingsContainer.setKeyguardShowing(true);
} else {
mKeyguardStatusView.setVisibility(View.GONE);
@@ -3034,10 +2786,10 @@
mKeyguardCarrierLabel.setVisibility(View.GONE);
mNotificationPanelHeader.setVisibility(View.VISIBLE);
- mKeyguardFlipper.setVisibility(View.GONE);
mSettingsContainer.setKeyguardShowing(false);
}
+ updateStackScrollerState();
updatePublicMode();
updateRowStates();
checkBarModes();
@@ -3045,6 +2797,10 @@
updateCarrierLabelVisibility(false);
}
+ public void updateStackScrollerState() {
+ mStackScroller.setDimmed(mState == StatusBarState.KEYGUARD, false /* animate */);
+ }
+
public void userActivity() {
if (mState == StatusBarState.KEYGUARD) {
mKeyguardViewMediatorCallback.userActivity();
@@ -3098,7 +2854,7 @@
public void onActivated(View view) {
userActivity();
mKeyguardIndicationTextView.switchIndication(R.string.notification_tap_again);
- super.onActivated(view);
+ mStackScroller.setActivatedChild(view);
}
/**
@@ -3110,9 +2866,11 @@
}
@Override
- public void onReset(View view) {
- super.onReset(view);
- mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
+ public void onActivationReset(View view) {
+ if (view == mStackScroller.getActivatedChild()) {
+ mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
+ mStackScroller.setActivatedChild(null);
+ }
}
public void onTrackingStarted() {
@@ -3144,30 +2902,12 @@
}
@Override
- public void onReset() {
- int n = mNotificationData.size();
- for (int i = 0; i < n; i++) {
- NotificationData.Entry entry = mNotificationData.get(i);
- if (entry.row.getVisibility() != View.GONE) {
- entry.row.setDimmed(true /* dimmed */, true /* fade */);
- }
- }
- if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) {
- mKeyguardIconOverflowContainer.setDimmed(true /* dimmed */, true /* fade */);
- }
+ public void onDragDownReset() {
+ mStackScroller.setDimmed(true /* dimmed */, true /* animated */);
}
public void onThresholdReached() {
- int n = mNotificationData.size();
- for (int i = 0; i < n; i++) {
- NotificationData.Entry entry = mNotificationData.get(i);
- if (entry.row.getVisibility() != View.GONE) {
- entry.row.setDimmed(false /* dimmed */, true /* fade */);
- }
- }
- if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) {
- mKeyguardIconOverflowContainer.setDimmed(false /* dimmed */, true /* fade */);
- }
+ mStackScroller.setDimmed(false /* dimmed */, true /* animate */);
}
/**
@@ -3201,131 +2941,6 @@
* @return a ViewGroup that spans the entire panel which contains the quick settings
*/
public ViewGroup getQuickSettingsOverlayParent() {
- if (mHasQuickSettings) {
- return mNotificationPanel;
- } else {
- return null;
- }
- }
-
- public static boolean inBounds(View view, MotionEvent event, boolean orAbove) {
- final int[] location = new int[2];
- view.getLocationInWindow(location);
- final int rx = (int) event.getRawX();
- final int ry = (int) event.getRawY();
- return rx >= location[0] && rx <= location[0] + view.getMeasuredWidth()
- && (orAbove || ry >= location[1]) && ry <= location[1] + view.getMeasuredHeight();
- }
-
- private final class FlipperButton {
- private final View mHolder;
-
- private ImageView mSettingsButton, mNotificationButton;
- private Animator mSettingsButtonAnim, mNotificationButtonAnim;
-
- public FlipperButton(View holder) {
- mHolder = holder;
- mSettingsButton = (ImageView) holder.findViewById(R.id.settings_button);
- if (mSettingsButton != null) {
- mSettingsButton.setOnClickListener(mSettingsButtonListener);
- if (mHasQuickSettings) {
- // the settings panel is hiding behind this button
- mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
- mSettingsButton.setVisibility(View.VISIBLE);
- } else {
- // no settings panel, go straight to settings
- mSettingsButton.setVisibility(View.VISIBLE);
- mSettingsButton.setImageResource(R.drawable.ic_notify_settings);
- }
- }
- mNotificationButton = (ImageView) holder.findViewById(R.id.notification_button);
- if (mNotificationButton != null) {
- mNotificationButton.setOnClickListener(mNotificationButtonListener);
- }
- }
-
- public boolean inHolderBounds(MotionEvent event) {
- return inBounds(mHolder, event, false);
- }
-
- public void provisionCheck(boolean provisioned) {
- if (mSettingsButton != null) {
- mSettingsButton.setEnabled(provisioned);
- }
- }
-
- public void userSetup(boolean userSetup) {
- if (mSettingsButton != null) {
- mSettingsButton.setVisibility(userSetup ? View.VISIBLE : View.INVISIBLE);
- }
- }
-
- public void reset() {
- cancel();
- mSettingsButton.setVisibility(View.VISIBLE);
- mNotificationButton.setVisibility(View.GONE);
- }
-
- public void refreshLayout() {
- if (mSettingsButton != null) {
- // Force asset reloading
- mSettingsButton.setImageDrawable(null);
- mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
- }
-
- if (mNotificationButton != null) {
- // Force asset reloading
- mNotificationButton.setImageDrawable(null);
- mNotificationButton.setImageResource(R.drawable.ic_notifications);
- }
- }
-
- public void flipToSettings(boolean animate) {
- mNotificationButton.setVisibility(View.VISIBLE);
- if (animate) {
- mSettingsButtonAnim = start(
- setVisibilityWhenDone(
- ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f)
- .setDuration(FLIP_DURATION_OUT),
- mStackScroller, View.INVISIBLE));
- mNotificationButtonAnim = start(
- startDelay(FLIP_DURATION_OUT,
- ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f)
- .setDuration(FLIP_DURATION_IN)));
- } else {
- mSettingsButton.setAlpha(0f);
- mSettingsButton.setVisibility(View.INVISIBLE);
- mNotificationButton.setAlpha(1f);
- }
- }
-
- public void flipToNotifications(boolean animate) {
- mSettingsButton.setVisibility(View.VISIBLE);
- if (animate) {
- mNotificationButtonAnim = start(
- setVisibilityWhenDone(
- ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f)
- .setDuration(FLIP_DURATION_OUT),
- mNotificationButton, View.INVISIBLE));
-
- mSettingsButtonAnim = start(
- startDelay(FLIP_DURATION_OUT,
- ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f)
- .setDuration(FLIP_DURATION_IN)));
- } else {
- mNotificationButton.setVisibility(View.INVISIBLE);
- mNotificationButton.setAlpha(0f);
- mSettingsButton.setAlpha(1f);
- }
- }
-
- public void cancel() {
- cancelAnim(mSettingsButtonAnim);
- cancelAnim(mNotificationButtonAnim);
- }
-
- public void setVisibility(int vis) {
- mHolder.setVisibility(vis);
- }
+ return mNotificationPanel;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 10c1625..e6de057 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -220,8 +220,6 @@
panel.setAlpha(alpha);
}
- mBar.animateHeadsUp(mNotificationPanel == panel, mPanelExpandedFractionSum);
-
mBar.updateCarrierLabelVisibility(false);
mBar.userActivity();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
new file mode 100644
index 0000000..9d33930
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+
+import com.android.systemui.R;
+
+/**
+ * The view to manage the header area in the expanded status bar.
+ */
+public class StatusBarHeaderView extends RelativeLayout {
+
+ private boolean mExpanded;
+ private View mBackground;
+ private View mFlipper;
+
+ private int mCollapsedHeight;
+ private int mExpandedHeight;
+
+ public StatusBarHeaderView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mBackground = findViewById(R.id.background);
+ mFlipper = findViewById(R.id.header_flipper);
+ loadDimens();
+ }
+
+ private void loadDimens() {
+ mCollapsedHeight = getResources().getDimensionPixelSize(
+ R.dimen.status_bar_header_height);
+ mExpandedHeight = getResources().getDimensionPixelSize(
+ R.dimen.status_bar_header_height_expanded);
+ }
+
+ public int getCollapsedHeight() {
+ return mCollapsedHeight;
+ }
+
+ public int getExpandedHeight() {
+ return mExpandedHeight;
+ }
+
+ public void setExpanded(boolean expanded) {
+ if (expanded != mExpanded) {
+ ViewGroup.LayoutParams lp = getLayoutParams();
+ lp.height = expanded ? mExpandedHeight : mCollapsedHeight;
+ setLayoutParams(lp);
+ mExpanded = expanded;
+ }
+ }
+
+ public void setExpansionEnabled(boolean enabled) {
+ mFlipper.setVisibility(enabled ? View.VISIBLE : View.GONE);
+ }
+
+ public void setExpansion(float height) {
+ if (height < mCollapsedHeight) {
+ height = mCollapsedHeight;
+ }
+ if (height > mExpandedHeight) {
+ height = mExpandedHeight;
+ }
+ if (mExpanded) {
+ mBackground.setTranslationY(-(mExpandedHeight - height));
+ } else {
+ mBackground.setTranslationY(0);
+ }
+ }
+
+ public View getBackgroundView() {
+ return mBackground;
+ }
+}
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 e24ddd9..f24c1b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -95,7 +95,9 @@
}
private void showBouncer() {
- mBouncer.show();
+ if (!mOccluded) {
+ mBouncer.show();
+ }
updateStates();
}
@@ -103,7 +105,12 @@
* Reset the state of the view.
*/
public void reset() {
- showBouncerOrKeyguard();
+ if (mOccluded) {
+ mPhoneStatusBar.hideKeyguard();
+ mBouncer.hide();
+ } else {
+ showBouncerOrKeyguard();
+ }
updateStates();
}
@@ -114,6 +121,7 @@
public void onScreenTurnedOn(final IKeyguardShowCallback callback) {
mScreenOn = true;
+ reset();
if (callback != null) {
callbackAfterDraw(callback);
}
@@ -147,7 +155,7 @@
public void setOccluded(boolean occluded) {
mOccluded = occluded;
mStatusBarWindowManager.setKeyguardOccluded(occluded);
- updateStates();
+ reset();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 4c9264d..e802d185 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -56,11 +56,14 @@
@Override
protected boolean fitSystemWindows(Rect insets) {
if (getFitsSystemWindows()) {
- setPadding(insets.left, insets.top, insets.right, insets.bottom);
+ setPadding(insets.left, insets.top, insets.right, 0);
+ insets.left = 0;
+ insets.top = 0;
+ insets.right = 0;
} else {
setPadding(0, 0, 0, 0);
}
- return true;
+ return false;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index 72e22e9..81e2cb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -237,6 +237,10 @@
}
@Override
+ public void onChildSnappedBack(View animView) {
+ }
+
+ @Override
public View getChildAtPosition(MotionEvent ev) {
return mContentHolder;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
new file mode 100644
index 0000000..4121a40
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.stack;
+
+import android.view.View;
+
+import java.util.ArrayList;
+
+/**
+ * A global state to track all input states for the algorithm.
+ */
+public class AmbientState {
+ private ArrayList<View> mDraggedViews = new ArrayList<View>();
+ private int mScrollY;
+ private boolean mDimmed;
+ private View mActivatedChild;
+
+ public int getScrollY() {
+ return mScrollY;
+ }
+
+ public void setScrollY(int scrollY) {
+ this.mScrollY = scrollY;
+ }
+
+ public void onBeginDrag(View view) {
+ mDraggedViews.add(view);
+ }
+
+ public void onDragFinished(View view) {
+ mDraggedViews.remove(view);
+ }
+
+ public ArrayList<View> getDraggedViews() {
+ return mDraggedViews;
+ }
+
+ /**
+ * @param dimmed Whether we are in a dimmed state (on the lockscreen), where the backgrounds are
+ * translucent and everything is scaled back a bit.
+ */
+ public void setDimmed(boolean dimmed) {
+ mDimmed = dimmed;
+ }
+
+ /**
+ * In dimmed mode, a child can be activated, which happens on the first tap of the double-tap
+ * interaction. This child is then scaled normally and its background is fully opaque.
+ */
+ public void setActivatedChild(View activatedChild) {
+ mActivatedChild = activatedChild;
+ }
+
+ public boolean isDimmed() {
+ return mDimmed;
+ }
+
+ public View getActivatedChild() {
+ return mActivatedChild;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
new file mode 100644
index 0000000..41914ed
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.stack;
+
+import java.util.ArrayList;
+
+/**
+ * Filters the animations for only a certain type of properties.
+ */
+public class AnimationFilter {
+ boolean animateAlpha;
+ boolean animateY;
+ boolean animateZ;
+ boolean animateScale;
+ boolean animateHeight;
+ boolean animateDimmed;
+
+ public AnimationFilter animateAlpha() {
+ animateAlpha = true;
+ return this;
+ }
+
+ public AnimationFilter animateY() {
+ animateY = true;
+ return this;
+ }
+
+ public AnimationFilter animateZ() {
+ animateZ = true;
+ return this;
+ }
+
+ public AnimationFilter animateScale() {
+ animateScale = true;
+ return this;
+ }
+
+ public AnimationFilter animateHeight() {
+ animateHeight = true;
+ return this;
+ }
+
+ public AnimationFilter animateDimmed() {
+ animateDimmed = true;
+ return this;
+ }
+
+ /**
+ * Combines multiple filters into {@code this} filter, using or as the operand .
+ *
+ * @param events The animation events from the filters to combine.
+ */
+ public void applyCombination(ArrayList<NotificationStackScrollLayout.AnimationEvent> events) {
+ reset();
+ int size = events.size();
+ for (int i = 0; i < size; i++) {
+ combineFilter(events.get(i).filter);
+ }
+ }
+
+ private void combineFilter(AnimationFilter filter) {
+ animateAlpha |= filter.animateAlpha;
+ animateY |= filter.animateY;
+ animateZ |= filter.animateZ;
+ animateScale |= filter.animateScale;
+ animateHeight |= filter.animateHeight;
+ animateDimmed |= filter.animateDimmed;
+ }
+
+ private void reset() {
+ animateAlpha = false;
+ animateY = false;
+ animateZ = false;
+ animateScale = false;
+ animateHeight = false;
+ animateDimmed = false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index e4e5fb1..afd5068 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -84,7 +84,6 @@
private int mEmptyMarginBottom;
private int mPaddingBetweenElements;
private int mTopPadding;
- private boolean mListenForHeightChanges = true;
/**
* The algorithm which calculates the properties for our children
@@ -95,8 +94,11 @@
* The current State this Layout is in
*/
private StackScrollState mCurrentStackScrollState = new StackScrollState(this);
+ private AmbientState mAmbientState = new AmbientState();
private ArrayList<View> mChildrenToAddAnimated = new ArrayList<View>();
private ArrayList<View> mChildrenToRemoveAnimated = new ArrayList<View>();
+ private ArrayList<View> mSnappedBackChildren = new ArrayList<View>();
+ private ArrayList<View> mDragAnimPendingChildren = new ArrayList<View>();
private ArrayList<AnimationEvent> mAnimationEvents
= new ArrayList<AnimationEvent>();
private ArrayList<View> mSwipedOutViews = new ArrayList<View>();
@@ -106,6 +108,8 @@
private ExpandableView.OnHeightChangedListener mOnHeightChangedListener;
private boolean mNeedsAnimation;
private boolean mTopPaddingNeedsAnimation;
+ private boolean mDimmedNeedsAnimation;
+ private boolean mActivateNeedsAnimation;
private boolean mIsExpanded = true;
private boolean mChildrenUpdateRequested;
private ViewTreeObserver.OnPreDrawListener mChildrenUpdater
@@ -265,8 +269,8 @@
* modifications to {@link #mOwnScrollY} are performed to reflect it in the view layout.
*/
private void updateChildren() {
- mCurrentStackScrollState.setScrollY(mOwnScrollY);
- mStackScrollAlgorithm.getStackScrollState(mCurrentStackScrollState);
+ mAmbientState.setScrollY(mOwnScrollY);
+ mStackScrollAlgorithm.getStackScrollState(mAmbientState, mCurrentStackScrollState);
if (!isCurrentlyAnimating() && !mNeedsAnimation) {
applyCurrentState();
} else {
@@ -377,11 +381,34 @@
veto.performClick();
}
setSwipingInProgress(false);
+ if (mDragAnimPendingChildren.contains(v)) {
+ // We start the swipe and finish it in the same frame, we don't want any animation
+ // for the drag
+ mDragAnimPendingChildren.remove(v);
+ }
mSwipedOutViews.add(v);
+ mAmbientState.onDragFinished(v);
+ }
+
+ @Override
+ public void onChildSnappedBack(View animView) {
+ mAmbientState.onDragFinished(animView);
+ if (!mDragAnimPendingChildren.contains(animView)) {
+ mSnappedBackChildren.add(animView);
+ requestChildrenUpdate();
+ mNeedsAnimation = true;
+ } else {
+ // We start the swipe and snap back in the same frame, we don't want any animation
+ mDragAnimPendingChildren.remove(animView);
+ }
}
public void onBeginDrag(View v) {
setSwipingInProgress(true);
+ mDragAnimPendingChildren.add(v);
+ mAmbientState.onBeginDrag(v);
+ requestChildrenUpdate();
+ mNeedsAnimation = true;
}
public void onDragCancelled(View v) {
@@ -467,6 +494,9 @@
@Override
public boolean onTouchEvent(MotionEvent ev) {
+ if (!isEnabled()) {
+ return false;
+ }
boolean scrollerWantsIt = false;
if (!mSwipingInProgress) {
scrollerWantsIt = onScrollTouch(ev);
@@ -486,7 +516,7 @@
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
- if (getChildCount() == 0) {
+ if (getChildCount() == 0 || !isInContentBounds(ev)) {
return false;
}
boolean isBeingDragged = !mScroller.isFinished();
@@ -934,12 +964,32 @@
private void generateChildHierarchyEvents() {
generateChildAdditionEvents();
generateChildRemovalEvents();
+ generateSnapBackEvents();
+ generateDragEvents();
generateTopPaddingEvent();
+ generateActivateEvent();
+ generateDimmedEvent();
mNeedsAnimation = false;
}
+ private void generateSnapBackEvents() {
+ for (View child : mSnappedBackChildren) {
+ mAnimationEvents.add(new AnimationEvent(child,
+ AnimationEvent.ANIMATION_TYPE_SNAP_BACK));
+ }
+ mSnappedBackChildren.clear();
+ }
+
+ private void generateDragEvents() {
+ for (View child : mDragAnimPendingChildren) {
+ mAnimationEvents.add(new AnimationEvent(child,
+ AnimationEvent.ANIMATION_TYPE_START_DRAG));
+ }
+ mDragAnimPendingChildren.clear();
+ }
+
private void generateChildRemovalEvents() {
- for (View child : mChildrenToRemoveAnimated) {
+ for (View child : mChildrenToRemoveAnimated) {
boolean childWasSwipedOut = mSwipedOutViews.contains(child);
int animationType = childWasSwipedOut
? AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT
@@ -951,7 +1001,7 @@
}
private void generateChildAdditionEvents() {
- for (View child : mChildrenToAddAnimated) {
+ for (View child : mChildrenToAddAnimated) {
mAnimationEvents.add(new AnimationEvent(child,
AnimationEvent.ANIMATION_TYPE_ADD));
}
@@ -966,6 +1016,22 @@
mTopPaddingNeedsAnimation = false;
}
+ private void generateActivateEvent() {
+ if (mActivateNeedsAnimation) {
+ mAnimationEvents.add(
+ new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_ACTIVATED_CHILD));
+ }
+ mActivateNeedsAnimation = false;
+ }
+
+ private void generateDimmedEvent() {
+ if (mDimmedNeedsAnimation) {
+ mAnimationEvents.add(
+ new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_DIMMED));
+ }
+ mDimmedNeedsAnimation = false;
+ }
+
private boolean onInterceptTouchEventScroll(MotionEvent ev) {
/*
* This method JUST determines whether we want to intercept the motion.
@@ -1074,6 +1140,13 @@
return mIsBeingDragged;
}
+ /**
+ * @return Whether the specified motion event is actually happening over the content.
+ */
+ private boolean isInContentBounds(MotionEvent event) {
+ return event.getY() < getHeight() - getEmptyBottomMargin();
+ }
+
private void setIsBeingDragged(boolean isDragged) {
mIsBeingDragged = isDragged;
if (isDragged) {
@@ -1131,14 +1204,12 @@
@Override
public void onHeightChanged(ExpandableView view) {
- if (mListenForHeightChanges && !isCurrentlyAnimating()) {
- updateContentHeight();
- updateScrollPositionIfNecessary();
- if (mOnHeightChangedListener != null) {
- mOnHeightChangedListener.onHeightChanged(view);
- }
- requestChildrenUpdate();
+ updateContentHeight();
+ updateScrollPositionIfNecessary();
+ if (mOnHeightChangedListener != null) {
+ mOnHeightChangedListener.onHeightChanged(view);
}
+ requestChildrenUpdate();
}
public void setOnHeightChangedListener(
@@ -1151,10 +1222,34 @@
mAnimationEvents.clear();
}
+ /**
+ * See {@link AmbientState#setDimmed}.
+ */
+ public void setDimmed(boolean dimmed, boolean animate) {
+ mAmbientState.setDimmed(dimmed);
+ if (animate) {
+ mDimmedNeedsAnimation = true;
+ mNeedsAnimation = true;
+ }
+ requestChildrenUpdate();
+ }
+
+ /**
+ * See {@link AmbientState#setActivatedChild}.
+ */
+ public void setActivatedChild(View activatedChild) {
+ mAmbientState.setActivatedChild(activatedChild);
+ mActivateNeedsAnimation = true;
+ mNeedsAnimation = true;
+ requestChildrenUpdate();
+ }
+
+ public View getActivatedChild() {
+ return mAmbientState.getActivatedChild();
+ }
+
private void applyCurrentState() {
- mListenForHeightChanges = false;
mCurrentStackScrollState.apply();
- mListenForHeightChanges = true;
if (mListener != null) {
mListener.onChildLocationsChanged(this);
}
@@ -1169,19 +1264,120 @@
static class AnimationEvent {
- static int ANIMATION_TYPE_ADD = 1;
- static int ANIMATION_TYPE_REMOVE = 2;
- static int ANIMATION_TYPE_REMOVE_SWIPED_OUT = 3;
- static int ANIMATION_TYPE_TOP_PADDING_CHANGED = 4;
+ static AnimationFilter[] FILTERS = new AnimationFilter[] {
+
+ // ANIMATION_TYPE_ADD
+ new AnimationFilter()
+ .animateAlpha()
+ .animateHeight()
+ .animateY()
+ .animateZ(),
+
+ // ANIMATION_TYPE_REMOVE
+ new AnimationFilter()
+ .animateAlpha()
+ .animateHeight()
+ .animateY()
+ .animateZ(),
+
+ // ANIMATION_TYPE_REMOVE_SWIPED_OUT
+ new AnimationFilter()
+ .animateAlpha()
+ .animateHeight()
+ .animateY()
+ .animateZ(),
+
+ // ANIMATION_TYPE_TOP_PADDING_CHANGED
+ new AnimationFilter()
+ .animateAlpha()
+ .animateHeight()
+ .animateY()
+ .animateDimmed()
+ .animateScale()
+ .animateZ(),
+
+ // ANIMATION_TYPE_START_DRAG
+ new AnimationFilter()
+ .animateAlpha(),
+
+ // ANIMATION_TYPE_SNAP_BACK
+ new AnimationFilter()
+ .animateAlpha(),
+
+ // ANIMATION_TYPE_ACTIVATED_CHILD
+ new AnimationFilter()
+ .animateScale()
+ .animateAlpha(),
+
+ // ANIMATION_TYPE_DIMMED
+ new AnimationFilter()
+ .animateScale()
+ .animateDimmed()
+ };
+
+ static int[] LENGTHS = new int[] {
+
+ // ANIMATION_TYPE_ADD
+ StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+ // ANIMATION_TYPE_REMOVE
+ StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+ // ANIMATION_TYPE_REMOVE_SWIPED_OUT
+ StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+ // ANIMATION_TYPE_TOP_PADDING_CHANGED
+ StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+ // ANIMATION_TYPE_START_DRAG
+ StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+ // ANIMATION_TYPE_SNAP_BACK
+ StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+ // ANIMATION_TYPE_ACTIVATED_CHILD
+ StackStateAnimator.ANIMATION_DURATION_DIMMED_ACTIVATED,
+
+ // ANIMATION_TYPE_DIMMED
+ StackStateAnimator.ANIMATION_DURATION_DIMMED_ACTIVATED,
+ };
+
+ static int ANIMATION_TYPE_ADD = 0;
+ static int ANIMATION_TYPE_REMOVE = 1;
+ static int ANIMATION_TYPE_REMOVE_SWIPED_OUT = 2;
+ static int ANIMATION_TYPE_TOP_PADDING_CHANGED = 3;
+ static int ANIMATION_TYPE_START_DRAG = 4;
+ static int ANIMATION_TYPE_SNAP_BACK = 5;
+ static int ANIMATION_TYPE_ACTIVATED_CHILD = 6;
+ static int ANIMATION_TYPE_DIMMED = 7;
final long eventStartTime;
final View changingView;
final int animationType;
+ final AnimationFilter filter;
+ final long length;
AnimationEvent(View view, int type) {
eventStartTime = AnimationUtils.currentAnimationTimeMillis();
changingView = view;
animationType = type;
+ filter = FILTERS[type];
+ length = LENGTHS[type];
+ }
+
+ /**
+ * Combines the length of several animation events into a single value.
+ *
+ * @param events The events of the lengths to combine.
+ * @return The combined length. This is just the maximum of all length.
+ */
+ static long combineLength(ArrayList<AnimationEvent> events) {
+ long length = 0;
+ int size = events.size();
+ for (int i = 0; i < size; i++) {
+ length = Math.max(length, events.get(i).length);
+ }
+ return length;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 09d8d50..5e4d496 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -39,6 +39,10 @@
private static final int MAX_ITEMS_IN_BOTTOM_STACK = 3;
private static final int MAX_ITEMS_IN_TOP_STACK = 3;
+ /** When a child is activated, the other cards' alpha fade to this value. */
+ private static final float ACTIVATED_INVERSE_ALPHA = 0.9f;
+ private static final float DIMMED_SCALE = 0.95f;
+
private int mPaddingBetweenElements;
private int mCollapsedSize;
private int mTopStackPeekSize;
@@ -92,7 +96,7 @@
}
- public void getStackScrollState(StackScrollState resultState) {
+ public void getStackScrollState(AmbientState ambientState, StackScrollState resultState) {
// The state of the local variables are saved in an algorithmState to easily subdivide it
// into multiple phases.
StackScrollAlgorithmState algorithmState = mTempAlgorithmState;
@@ -106,7 +110,7 @@
algorithmState.scrolledPixelsTop = 0;
algorithmState.itemsInBottomStack = 0.0f;
algorithmState.partialInBottom = 0.0f;
- algorithmState.scrollY = resultState.getScrollY() + mCollapsedSize;
+ algorithmState.scrollY = ambientState.getScrollY() + mCollapsedSize;
updateVisibleChildren(resultState, algorithmState);
@@ -118,6 +122,57 @@
// Phase 3:
updateZValuesForState(resultState, algorithmState);
+
+ handleDraggedViews(ambientState, resultState, algorithmState);
+ updateDimmedActivated(ambientState, resultState, algorithmState);
+ }
+
+ /**
+ * Updates the dimmed and activated states of the children.
+ */
+ private void updateDimmedActivated(AmbientState ambientState, StackScrollState resultState,
+ StackScrollAlgorithmState algorithmState) {
+ boolean dimmed = ambientState.isDimmed();
+ View activatedChild = ambientState.getActivatedChild();
+ int childCount = algorithmState.visibleChildren.size();
+ for (int i = 0; i < childCount; i++) {
+ View child = algorithmState.visibleChildren.get(i);
+ StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
+ childViewState.dimmed = dimmed;
+ childViewState.scale = !dimmed || activatedChild == child
+ ? 1.0f
+ : DIMMED_SCALE;
+ if (dimmed && activatedChild != null && child != activatedChild) {
+ childViewState.alpha *= ACTIVATED_INVERSE_ALPHA;
+ }
+ }
+ }
+
+ /**
+ * Handle the special state when views are being dragged
+ */
+ private void handleDraggedViews(AmbientState ambientState, StackScrollState resultState,
+ StackScrollAlgorithmState algorithmState) {
+ ArrayList<View> draggedViews = ambientState.getDraggedViews();
+ for (View draggedView : draggedViews) {
+ int childIndex = algorithmState.visibleChildren.indexOf(draggedView);
+ if (childIndex >= 0 && childIndex < algorithmState.visibleChildren.size() - 1) {
+ View nextChild = algorithmState.visibleChildren.get(childIndex + 1);
+ if (!draggedViews.contains(nextChild)) {
+ // only if the view is not dragged itself we modify its state to be fully
+ // visible
+ StackScrollState.ViewState viewState = resultState.getViewStateForView(
+ nextChild);
+ // The child below the dragged one must be fully visible
+ viewState.alpha = 1;
+ }
+
+ // Lets set the alpha to the one it currently has, as its currently being dragged
+ StackScrollState.ViewState viewState = resultState.getViewStateForView(draggedView);
+ // The dragged child should keep the set alpha
+ viewState.alpha = draggedView.getAlpha();
+ }
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 26cef36..8fc26d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -37,19 +37,10 @@
private final ViewGroup mHostView;
private Map<ExpandableView, ViewState> mStateMap;
- private int mScrollY;
private final Rect mClipRect = new Rect();
private int mBackgroundRoundedRectCornerRadius;
private final Outline mChildOutline = new Outline();
- public int getScrollY() {
- return mScrollY;
- }
-
- public void setScrollY(int scrollY) {
- this.mScrollY = scrollY;
- }
-
public StackScrollState(ViewGroup hostView) {
mHostView = hostView;
mStateMap = new HashMap<ExpandableView, ViewState>();
@@ -93,6 +84,7 @@
int numChildren = mHostView.getChildCount();
float previousNotificationEnd = 0;
float previousNotificationStart = 0;
+ boolean previousNotificationIsSwiped = false;
for (int i = 0; i < numChildren; i++) {
ExpandableView child = (ExpandableView) mHostView.getChildAt(i);
ViewState state = mStateMap.get(child);
@@ -105,10 +97,12 @@
float alpha = child.getAlpha();
float yTranslation = child.getTranslationY();
float zTranslation = child.getTranslationZ();
+ float scale = child.getScaleX();
int height = child.getActualHeight();
float newAlpha = state.alpha;
float newYTranslation = state.yTranslation;
float newZTranslation = state.zTranslation;
+ float newScale = state.scale;
int newHeight = state.height;
boolean becomesInvisible = newAlpha == 0.0f;
if (alpha != newAlpha) {
@@ -146,19 +140,36 @@
child.setTranslationZ(newZTranslation);
}
+ // apply scale
+ if (scale != newScale) {
+ child.setScaleX(newScale);
+ child.setScaleY(newScale);
+ }
+
// apply height
if (height != newHeight) {
- child.setActualHeight(newHeight);
+ child.setActualHeight(newHeight, false /* notifyListeners */);
}
+ // apply dimming
+ child.setDimmed(state.dimmed, false /* animate */);
+
// apply clipping and shadow
float newNotificationEnd = newYTranslation + newHeight;
+
+ // When the previous notification is swiped, we don't clip the content to the
+ // bottom of it.
+ float clipHeight = previousNotificationIsSwiped
+ ? newHeight
+ : newNotificationEnd - (previousNotificationEnd);
+
updateChildClippingAndBackground(child, newHeight,
- newNotificationEnd - (previousNotificationEnd),
+ clipHeight,
(int) (newHeight - (previousNotificationStart - newYTranslation)));
- previousNotificationStart = newYTranslation;
+ previousNotificationStart = newYTranslation + child.getClipTopAmount();
previousNotificationEnd = newNotificationEnd;
+ previousNotificationIsSwiped = child.getTranslationX() != 0;
}
}
}
@@ -219,6 +230,8 @@
float zTranslation;
int height;
boolean gone;
+ float scale;
+ boolean dimmed;
/**
* The location this view is currently rendered at.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 4dce288..ca383aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -16,144 +16,519 @@
package com.android.systemui.statusbar.stack;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+
+import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableView;
import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Stack;
/**
* An stack state animator which handles animations to new StackScrollStates
*/
public class StackStateAnimator {
- private static final int ANIMATION_DURATION = 360;
+ public static final int ANIMATION_DURATION_STANDARD = 360;
+ public static final int ANIMATION_DURATION_DIMMED_ACTIVATED = 220;
+
+ private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
+ private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
+ private static final int TAG_ANIMATOR_SCALE = R.id.scale_animator_tag;
+ private static final int TAG_ANIMATOR_ALPHA = R.id.alpha_animator_tag;
+ private static final int TAG_ANIMATOR_HEIGHT = R.id.height_animator_tag;
+ private static final int TAG_ANIMATOR_TOP_INSET = R.id.top_inset_animator_tag;
+ private static final int TAG_END_TRANSLATION_Y = R.id.translation_y_animator_end_value_tag;
+ private static final int TAG_END_TRANSLATION_Z = R.id.translation_z_animator_end_value_tag;
+ private static final int TAG_END_SCALE = R.id.scale_animator_end_value_tag;
+ private static final int TAG_END_ALPHA = R.id.alpha_animator_end_value_tag;
+ private static final int TAG_END_HEIGHT = R.id.height_animator_end_value_tag;
+ private static final int TAG_END_TOP_INSET = R.id.top_inset_animator_end_value_tag;
+ private static final int TAG_START_TRANSLATION_Y = R.id.translation_y_animator_start_value_tag;
+ private static final int TAG_START_TRANSLATION_Z = R.id.translation_z_animator_start_value_tag;
+ private static final int TAG_START_SCALE = R.id.scale_animator_start_value_tag;
+ private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag;
+ private static final int TAG_START_HEIGHT = R.id.height_animator_start_value_tag;
+ private static final int TAG_START_TOP_INSET = R.id.top_inset_animator_start_value_tag;
private final Interpolator mFastOutSlowInInterpolator;
public NotificationStackScrollLayout mHostLayout;
- private boolean mAnimationIsRunning;
private ArrayList<NotificationStackScrollLayout.AnimationEvent> mHandledEvents =
new ArrayList<>();
+ private ArrayList<NotificationStackScrollLayout.AnimationEvent> mNewEvents =
+ new ArrayList<>();
+ private Set<Animator> mAnimatorSet = new HashSet<Animator>();
+ private Stack<AnimatorListenerAdapter> mAnimationListenerPool
+ = new Stack<AnimatorListenerAdapter>();
+ private AnimationFilter mAnimationFilter = new AnimationFilter();
+ private long mCurrentLength;
public StackStateAnimator(NotificationStackScrollLayout hostLayout) {
mHostLayout = hostLayout;
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(hostLayout.getContext(),
- android.R.interpolator.fast_out_slow_in);
+ android.R.interpolator.fast_out_slow_in);
}
public boolean isRunning() {
- return mAnimationIsRunning;
+ return !mAnimatorSet.isEmpty();
}
public void startAnimationForEvents(
ArrayList<NotificationStackScrollLayout.AnimationEvent> mAnimationEvents,
StackScrollState finalState) {
- int numEvents = mAnimationEvents.size();
- if (numEvents == 0) {
- // No events, so we don't perform any animation
- return;
- }
- long lastEventStartTime = mAnimationEvents.get(numEvents - 1).eventStartTime;
- long eventEnd = lastEventStartTime + ANIMATION_DURATION;
- long currentTime = AnimationUtils.currentAnimationTimeMillis();
- long newDuration = eventEnd - currentTime;
- if (newDuration <= 0) {
- // last event is long before this, so we don't do anything
- return;
- }
- initializeAddedViewStates(mAnimationEvents, finalState);
+
+ processAnimationEvents(mAnimationEvents, finalState);
+
int childCount = mHostLayout.getChildCount();
- boolean isFirstAnimatingView = true;
+ mAnimationFilter.applyCombination(mNewEvents);
+ mCurrentLength = NotificationStackScrollLayout.AnimationEvent.combineLength(mNewEvents);
for (int i = 0; i < childCount; i++) {
final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
StackScrollState.ViewState viewState = finalState.getViewStateForView(child);
if (viewState == null) {
continue;
}
- int childVisibility = child.getVisibility();
- boolean wasVisible = childVisibility == View.VISIBLE;
- final float alpha = viewState.alpha;
- if (!wasVisible && alpha != 0 && !viewState.gone) {
- child.setVisibility(View.VISIBLE);
- }
- startPropertyAnimation(newDuration, isFirstAnimatingView, child, viewState, alpha);
+ startAnimations(child, viewState);
- // TODO: animate clipBounds
child.setClipBounds(null);
- int currentHeigth = child.getActualHeight();
- if (viewState.height != currentHeigth) {
- startHeightAnimation(newDuration, child, viewState, currentHeigth);
- }
- isFirstAnimatingView = false;
}
- mAnimationIsRunning = true;
- }
-
- private void startPropertyAnimation(long newDuration, final boolean hasFinishAction,
- final ExpandableView child, StackScrollState.ViewState viewState, final float alpha) {
- child.animate().setInterpolator(mFastOutSlowInInterpolator)
- .translationY(viewState.yTranslation)
- .translationZ(viewState.zTranslation)
- .setDuration(newDuration)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- mAnimationIsRunning = false;
- if (hasFinishAction) {
- mHandledEvents.clear();
- mHostLayout.onChildAnimationFinished();
- }
- if (alpha == 0) {
- child.setVisibility(View.INVISIBLE);
- }
- }
- });
- if (alpha != child.getAlpha()) {
- child.animate().withLayer().alpha(alpha);
+ if (!isRunning()) {
+ // no child has preformed any animation, lets finish
+ onAnimationFinished();
}
}
- private void startHeightAnimation(long newDuration, final ExpandableView child,
- StackScrollState.ViewState viewState, int currentHeigth) {
- ValueAnimator heightAnimator = ValueAnimator.ofInt(currentHeigth, viewState.height);
- heightAnimator.setInterpolator(mFastOutSlowInInterpolator);
- heightAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- child.setActualHeight((int) animation.getAnimatedValue());
- }
- });
- heightAnimator.setDuration(newDuration);
- heightAnimator.start();
- }
-
/**
- * Initialize the viewStates for the added children
+ * Start an animation to the given viewState
+ */
+ private void startAnimations(final ExpandableView child, StackScrollState.ViewState viewState) {
+ int childVisibility = child.getVisibility();
+ boolean wasVisible = childVisibility == View.VISIBLE;
+ final float alpha = viewState.alpha;
+ if (!wasVisible && alpha != 0 && !viewState.gone) {
+ child.setVisibility(View.VISIBLE);
+ }
+ // start translationY animation
+ if (child.getTranslationY() != viewState.yTranslation) {
+ startYTranslationAnimation(child, viewState);
+ }
+ // start translationZ animation
+ if (child.getTranslationZ() != viewState.zTranslation) {
+ startZTranslationAnimation(child, viewState);
+ }
+ // start scale animation
+ if (child.getScaleX() != viewState.scale) {
+ startScaleAnimation(child, viewState);
+ }
+ // start alpha animation
+ if (alpha != child.getAlpha()) {
+ startAlphaAnimation(child, viewState);
+ }
+ // start height animation
+ if (viewState.height != child.getActualHeight()) {
+ startHeightAnimation(child, viewState);
+ }
+ // start dimmed animation
+ child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed);
+ }
+
+ private void startHeightAnimation(final ExpandableView child,
+ StackScrollState.ViewState viewState) {
+ Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT);
+ Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT);
+ int newEndValue = viewState.height;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_HEIGHT);
+ if (!mAnimationFilter.animateHeight) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ int relativeDiff = newEndValue - previousEndValue;
+ int newStartValue = previousStartValue + relativeDiff;
+ values[0].setIntValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_HEIGHT, newStartValue);
+ child.setTag(TAG_END_HEIGHT, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setActualHeight(newEndValue, false);
+ return;
+ }
+ }
+
+ ValueAnimator animator = ValueAnimator.ofInt(child.getActualHeight(), newEndValue);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ child.setActualHeight((int) animation.getAnimatedValue(),
+ false /* notifyListeners */);
+ }
+ });
+ animator.setInterpolator(mFastOutSlowInInterpolator);
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+ animator.setDuration(newDuration);
+ animator.addListener(getGlobalAnimationFinishedListener());
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_HEIGHT, null);
+ child.setTag(TAG_START_HEIGHT, null);
+ child.setTag(TAG_END_HEIGHT, null);
+ }
+ });
+ startInstantly(animator);
+ child.setTag(TAG_ANIMATOR_HEIGHT, animator);
+ child.setTag(TAG_START_HEIGHT, child.getActualHeight());
+ child.setTag(TAG_END_HEIGHT, newEndValue);
+ }
+
+ private void startAlphaAnimation(final ExpandableView child,
+ final StackScrollState.ViewState viewState) {
+ Float previousStartValue = getChildTag(child,TAG_START_ALPHA);
+ Float previousEndValue = getChildTag(child,TAG_END_ALPHA);
+ final float newEndValue = viewState.alpha;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_ALPHA);
+ if (!mAnimationFilter.animateAlpha) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_ALPHA, newStartValue);
+ child.setTag(TAG_END_ALPHA, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setAlpha(newEndValue);
+ if (newEndValue == 0) {
+ child.setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.ALPHA,
+ child.getAlpha(), newEndValue);
+ animator.setInterpolator(mFastOutSlowInInterpolator);
+ // Handle layer type
+ final int currentLayerType = child.getLayerType();
+ child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ animator.addListener(new AnimatorListenerAdapter() {
+ public boolean mWasCancelled;
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setLayerType(currentLayerType, null);
+ if (newEndValue == 0 && !mWasCancelled) {
+ child.setVisibility(View.INVISIBLE);
+ }
+ child.setTag(TAG_ANIMATOR_ALPHA, null);
+ child.setTag(TAG_START_ALPHA, null);
+ child.setTag(TAG_END_ALPHA, null);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mWasCancelled = true;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mWasCancelled = false;
+ }
+ });
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+ animator.setDuration(newDuration);
+ animator.addListener(getGlobalAnimationFinishedListener());
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+
+ }
+ });
+ startInstantly(animator);
+ child.setTag(TAG_ANIMATOR_ALPHA, animator);
+ child.setTag(TAG_START_ALPHA, child.getAlpha());
+ child.setTag(TAG_END_ALPHA, newEndValue);
+ }
+
+ private void startZTranslationAnimation(final ExpandableView child,
+ final StackScrollState.ViewState viewState) {
+ Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z);
+ Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z);
+ float newEndValue = viewState.zTranslation;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Z);
+ if (!mAnimationFilter.animateZ) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_TRANSLATION_Z, newStartValue);
+ child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setTranslationZ(newEndValue);
+ }
+ }
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Z,
+ child.getTranslationZ(), newEndValue);
+ animator.setInterpolator(mFastOutSlowInInterpolator);
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+ animator.setDuration(newDuration);
+ animator.addListener(getGlobalAnimationFinishedListener());
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Z, null);
+ child.setTag(TAG_START_TRANSLATION_Z, null);
+ child.setTag(TAG_END_TRANSLATION_Z, null);
+ }
+ });
+ startInstantly(animator);
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Z, animator);
+ child.setTag(TAG_START_TRANSLATION_Z, child.getTranslationZ());
+ child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
+ }
+
+ private void startYTranslationAnimation(final ExpandableView child,
+ StackScrollState.ViewState viewState) {
+ Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y);
+ Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y);
+ float newEndValue = viewState.yTranslation;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y);
+ if (!mAnimationFilter.animateY) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_TRANSLATION_Y, newStartValue);
+ child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setTranslationY(newEndValue);
+ return;
+ }
+ }
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Y,
+ child.getTranslationY(), newEndValue);
+ animator.setInterpolator(mFastOutSlowInInterpolator);
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+ animator.setDuration(newDuration);
+ animator.addListener(getGlobalAnimationFinishedListener());
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null);
+ child.setTag(TAG_START_TRANSLATION_Y, null);
+ child.setTag(TAG_END_TRANSLATION_Y, null);
+ }
+ });
+ startInstantly(animator);
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Y, animator);
+ child.setTag(TAG_START_TRANSLATION_Y, child.getTranslationY());
+ child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
+ }
+
+ private void startScaleAnimation(final ExpandableView child,
+ StackScrollState.ViewState viewState) {
+ Float previousStartValue = getChildTag(child, TAG_START_SCALE);
+ Float previousEndValue = getChildTag(child, TAG_END_SCALE);
+ float newEndValue = viewState.scale;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_SCALE);
+ if (!mAnimationFilter.animateScale) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ values[1].setFloatValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_SCALE, newStartValue);
+ child.setTag(TAG_END_SCALE, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setScaleX(newEndValue);
+ child.setScaleY(newEndValue);
+ }
+ }
+
+ PropertyValuesHolder holderX =
+ PropertyValuesHolder.ofFloat(View.SCALE_X, child.getScaleX(), newEndValue);
+ PropertyValuesHolder holderY =
+ PropertyValuesHolder.ofFloat(View.SCALE_Y, child.getScaleY(), newEndValue);
+ ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(child, holderX, holderY);
+ animator.setInterpolator(mFastOutSlowInInterpolator);
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+ animator.setDuration(newDuration);
+ animator.addListener(getGlobalAnimationFinishedListener());
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_SCALE, null);
+ child.setTag(TAG_START_SCALE, null);
+ child.setTag(TAG_END_SCALE, null);
+ }
+ });
+ startInstantly(animator);
+ child.setTag(TAG_ANIMATOR_SCALE, animator);
+ child.setTag(TAG_START_SCALE, child.getScaleX());
+ child.setTag(TAG_END_SCALE, newEndValue);
+ }
+
+ /**
+ * Start an animator instantly instead of waiting on the next synchronization frame
+ */
+ private void startInstantly(ValueAnimator animator) {
+ animator.start();
+ animator.setCurrentPlayTime(0);
+ }
+
+ /**
+ * @return an adapter which ensures that onAnimationFinished is called once no animation is
+ * running anymore
+ */
+ private AnimatorListenerAdapter getGlobalAnimationFinishedListener() {
+ if (!mAnimationListenerPool.empty()) {
+ return mAnimationListenerPool.pop();
+ }
+
+ // We need to create a new one, no reusable ones found
+ return new AnimatorListenerAdapter() {
+ private boolean mWasCancelled;
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnimatorSet.remove(animation);
+ if (mAnimatorSet.isEmpty() && !mWasCancelled) {
+ onAnimationFinished();
+ }
+ mAnimationListenerPool.push(this);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mWasCancelled = true;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mAnimatorSet.add(animation);
+ mWasCancelled = false;
+ }
+ };
+ }
+
+ private <T> T getChildTag(View child, int tag) {
+ return (T) child.getTag(tag);
+ }
+
+ /**
+ * Cancel the previous animator and get the duration of the new animation.
*
- * @param animationEvents the animation events who contain the added children
+ * @param previousAnimator the animator which was running before
+ * @return the new duration
+ */
+ private long cancelAnimatorAndGetNewDuration(ValueAnimator previousAnimator) {
+ long newDuration = mCurrentLength;
+ if (previousAnimator != null) {
+ // We take either the desired length of the new animation or the remaining time of
+ // the previous animator, whichever is longer.
+ newDuration = Math.max(previousAnimator.getDuration()
+ - previousAnimator.getCurrentPlayTime(), newDuration);
+ previousAnimator.cancel();
+ }
+ return newDuration;
+ }
+
+ private void onAnimationFinished() {
+ mHandledEvents.clear();
+ mNewEvents.clear();
+ mHostLayout.onChildAnimationFinished();
+ }
+
+ /**
+ * Process the animationEvents for a new animation
+ *
+ * @param animationEvents the animation events for the animation to perform
* @param finalState the final state to animate to
*/
- private void initializeAddedViewStates(
+ private void processAnimationEvents(
ArrayList<NotificationStackScrollLayout.AnimationEvent> animationEvents,
StackScrollState finalState) {
+ mNewEvents.clear();
for (NotificationStackScrollLayout.AnimationEvent event: animationEvents) {
View changingView = event.changingView;
- if (event.animationType == NotificationStackScrollLayout.AnimationEvent
- .ANIMATION_TYPE_ADD && !mHandledEvents.contains(event)) {
+ if (!mHandledEvents.contains(event)) {
+ if (event.animationType == NotificationStackScrollLayout.AnimationEvent
+ .ANIMATION_TYPE_ADD) {
- // This item is added, initialize it's properties.
- StackScrollState.ViewState viewState = finalState.getViewStateForView(changingView);
- if (viewState == null) {
- // The position for this child was never generated, let's continue.
- continue;
+ // This item is added, initialize it's properties.
+ StackScrollState.ViewState viewState = finalState
+ .getViewStateForView(changingView);
+ if (viewState == null) {
+ // The position for this child was never generated, let's continue.
+ continue;
+ }
+ changingView.setAlpha(0);
+ changingView.setTranslationY(viewState.yTranslation);
+ changingView.setTranslationZ(viewState.zTranslation);
}
- changingView.setAlpha(0);
- changingView.setTranslationY(viewState.yTranslation);
- changingView.setTranslationZ(viewState.zTranslation);
mHandledEvents.add(event);
+ mNewEvents.add(event);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index d615542..9006c9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -78,7 +78,8 @@
}
@Override
- public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
+ public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher) {
}
@Override
@@ -120,11 +121,6 @@
}
@Override
- protected int getExpandedViewMaxHeight() {
- return 0;
- }
-
- @Override
protected boolean shouldDisableNavbarGestures() {
return true;
}
@@ -154,4 +150,11 @@
protected void refreshLayout(int layoutDirection) {
}
+ @Override
+ public void onActivated(View view) {
+ }
+
+ @Override
+ public void onActivationReset(View view) {
+ }
}
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index dce4f581..a62d1fd 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -63,6 +63,25 @@
static Method registerNativeAllocation;
static Method registerNativeFree;
+ /*
+ * Context creation flag which specifies a normal context.
+ */
+ public static final long CREATE_FLAG_NONE = 0x0000;
+
+ /*
+ * Context creation flag which specifies a context optimized for low
+ * latency over peak performance. This is a hint and may have no effect
+ * on some implementations.
+ */
+ public static final long CREATE_FLAG_LOW_LATENCY = 0x0001;
+
+ /*
+ * Context creation flag which specifies a context optimized for long
+ * battery life over peak performance. This is a hint and may have no effect
+ * on some implementations.
+ */
+ public static final long CREATE_FLAG_LOW_POWER = 0x0002;
+
static {
sInitialized = false;
if (!SystemProperties.getBoolean("config.disable_renderscript", false)) {
@@ -1145,7 +1164,7 @@
* @hide
*/
public static RenderScript create(Context ctx, int sdkVersion) {
- return create(ctx, sdkVersion, ContextType.NORMAL);
+ return create(ctx, sdkVersion, ContextType.NORMAL, CREATE_FLAG_NONE);
}
/**
@@ -1155,7 +1174,7 @@
* @param ctx The context.
* @return RenderScript
*/
- public static RenderScript create(Context ctx, int sdkVersion, ContextType ct) {
+ public static RenderScript create(Context ctx, int sdkVersion, ContextType ct, long flags) {
if (!sInitialized) {
Log.e(LOG_TAG, "RenderScript.create() called when disabled; someone is likely to crash");
return null;
@@ -1194,7 +1213,21 @@
*/
public static RenderScript create(Context ctx, ContextType ct) {
int v = ctx.getApplicationInfo().targetSdkVersion;
- return create(ctx, v, ct);
+ return create(ctx, v, ct, CREATE_FLAG_NONE);
+ }
+
+ /**
+ * Create a RenderScript context.
+ *
+ *
+ * @param ctx The context.
+ * @param ct The type of context to be created.
+ * @param flags The OR of the CREATE_FLAG_* options desired
+ * @return RenderScript
+ */
+ public static RenderScript create(Context ctx, ContextType ct, long flags) {
+ int v = ctx.getApplicationInfo().targetSdkVersion;
+ return create(ctx, v, ct, flags);
}
/**
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index 07933b4..f1ddc07 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -27,7 +27,6 @@
LOCAL_CFLAGS += -Wno-unused-parameter
-LOCAL_LDLIBS := -lpthread
LOCAL_ADDITIONAL_DEPENDENCIES := $(addprefix $(rs_generated_include_dir)/,rsgApiFuncDecl.h)
LOCAL_MODULE:= librs_jni
LOCAL_ADDITIONAL_DEPENDENCIES += $(rs_generated_source)
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 45cdb65..dfffa8a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -74,7 +74,7 @@
import android.net.NetworkUtils;
import android.net.Proxy;
import android.net.ProxyDataTracker;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.SamplingDataTracker;
import android.net.Uri;
@@ -406,12 +406,12 @@
private ArrayList mInetLog;
// track the current default http proxy - tell the world if we get a new one (real change)
- private ProxyProperties mDefaultProxy = null;
+ private ProxyInfo mDefaultProxy = null;
private Object mProxyLock = new Object();
private boolean mDefaultProxyDisabled = false;
// track the global proxy.
- private ProxyProperties mGlobalProxy = null;
+ private ProxyInfo mGlobalProxy = null;
private PacManager mPacManager = null;
@@ -3192,7 +3192,7 @@
break;
}
case EVENT_PROXY_HAS_CHANGED: {
- handleApplyDefaultProxy((ProxyProperties)msg.obj);
+ handleApplyDefaultProxy((ProxyInfo)msg.obj);
break;
}
}
@@ -3410,19 +3410,19 @@
return;
}
- public ProxyProperties getProxy() {
+ public ProxyInfo getProxy() {
// this information is already available as a world read/writable jvm property
// so this API change wouldn't have a benifit. It also breaks the passing
// of proxy info to all the JVMs.
// enforceAccessPermission();
synchronized (mProxyLock) {
- ProxyProperties ret = mGlobalProxy;
+ ProxyInfo ret = mGlobalProxy;
if ((ret == null) && !mDefaultProxyDisabled) ret = mDefaultProxy;
return ret;
}
}
- public void setGlobalProxy(ProxyProperties proxyProperties) {
+ public void setGlobalProxy(ProxyInfo proxyProperties) {
enforceConnectivityInternalPermission();
synchronized (mProxyLock) {
@@ -3435,18 +3435,18 @@
String exclList = "";
String pacFileUrl = "";
if (proxyProperties != null && (!TextUtils.isEmpty(proxyProperties.getHost()) ||
- !TextUtils.isEmpty(proxyProperties.getPacFileUrl()))) {
+ (proxyProperties.getPacFileUrl() != null))) {
if (!proxyProperties.isValid()) {
if (DBG)
log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
return;
}
- mGlobalProxy = new ProxyProperties(proxyProperties);
+ mGlobalProxy = new ProxyInfo(proxyProperties);
host = mGlobalProxy.getHost();
port = mGlobalProxy.getPort();
- exclList = mGlobalProxy.getExclusionList();
+ exclList = mGlobalProxy.getExclusionListAsString();
if (proxyProperties.getPacFileUrl() != null) {
- pacFileUrl = proxyProperties.getPacFileUrl();
+ pacFileUrl = proxyProperties.getPacFileUrl().toString();
}
} else {
mGlobalProxy = null;
@@ -3478,11 +3478,11 @@
Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
String pacFileUrl = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC);
if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
- ProxyProperties proxyProperties;
+ ProxyInfo proxyProperties;
if (!TextUtils.isEmpty(pacFileUrl)) {
- proxyProperties = new ProxyProperties(pacFileUrl);
+ proxyProperties = new ProxyInfo(pacFileUrl);
} else {
- proxyProperties = new ProxyProperties(host, port, exclList);
+ proxyProperties = new ProxyInfo(host, port, exclList);
}
if (!proxyProperties.isValid()) {
if (DBG) log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
@@ -3495,7 +3495,7 @@
}
}
- public ProxyProperties getGlobalProxy() {
+ public ProxyInfo getGlobalProxy() {
// this information is already available as a world read/writable jvm property
// so this API change wouldn't have a benifit. It also breaks the passing
// of proxy info to all the JVMs.
@@ -3505,9 +3505,9 @@
}
}
- private void handleApplyDefaultProxy(ProxyProperties proxy) {
+ private void handleApplyDefaultProxy(ProxyInfo proxy) {
if (proxy != null && TextUtils.isEmpty(proxy.getHost())
- && TextUtils.isEmpty(proxy.getPacFileUrl())) {
+ && (proxy.getPacFileUrl() == null)) {
proxy = null;
}
synchronized (mProxyLock) {
@@ -3517,6 +3517,18 @@
if (DBG) log("Invalid proxy properties, ignoring: " + proxy.toString());
return;
}
+
+ // This call could be coming from the PacManager, containing the port of the local
+ // proxy. If this new proxy matches the global proxy then copy this proxy to the
+ // global (to get the correct local port), and send a broadcast.
+ // TODO: Switch PacManager to have its own message to send back rather than
+ // reusing EVENT_HAS_CHANGED_PROXY and this call to handleApplyDefaultProxy.
+ if ((mGlobalProxy != null) && (proxy != null) && (proxy.getPacFileUrl() != null)
+ && proxy.getPacFileUrl().equals(mGlobalProxy.getPacFileUrl())) {
+ mGlobalProxy = proxy;
+ sendProxyBroadcast(mGlobalProxy);
+ return;
+ }
mDefaultProxy = proxy;
if (mGlobalProxy != null) return;
@@ -3544,13 +3556,13 @@
return;
}
}
- ProxyProperties p = new ProxyProperties(data[0], proxyPort, "");
+ ProxyInfo p = new ProxyInfo(data[0], proxyPort, "");
setGlobalProxy(p);
}
}
- private void sendProxyBroadcast(ProxyProperties proxy) {
- if (proxy == null) proxy = new ProxyProperties("", 0, "");
+ private void sendProxyBroadcast(ProxyInfo proxy) {
+ if (proxy == null) proxy = new ProxyInfo("", 0, "");
if (mPacManager.setCurrentProxyScriptUrl(proxy)) return;
if (DBG) log("sending Proxy Broadcast for " + proxy);
Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 7ed1cc7..10315a7 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -1532,14 +1532,17 @@
}
mImeWindowVis = vis;
mBackDisposition = backDisposition;
- if (mStatusBar != null) {
- mStatusBar.setImeWindowStatus(token, vis, backDisposition);
- }
final boolean iconVisibility = ((vis & (InputMethodService.IME_ACTIVE)) != 0)
&& (mWindowManagerService.isHardKeyboardAvailable()
|| (vis & (InputMethodService.IME_VISIBLE)) != 0);
+ final boolean needsToShowImeSwitcher = iconVisibility
+ && needsToShowImeSwitchOngoingNotification();
+ if (mStatusBar != null) {
+ mStatusBar.setImeWindowStatus(token, vis, backDisposition,
+ needsToShowImeSwitcher);
+ }
final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
- if (imi != null && iconVisibility && needsToShowImeSwitchOngoingNotification()) {
+ if (imi != null && needsToShowImeSwitcher) {
// Used to load label
final CharSequence title = mRes.getText(
com.android.internal.R.string.select_input_method);
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 7ec9b82..d5f045e 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -201,8 +201,8 @@
public static final String[] CRYPTO_TYPES
= { "password", "default", "pattern", "pin" };
- private Context mContext;
- private NativeDaemonConnector mConnector;
+ private final Context mContext;
+ private final NativeDaemonConnector mConnector;
private final Object mVolumesLock = new Object();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cbb8377..efc5606 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -136,7 +136,7 @@
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Proxy;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -983,7 +983,7 @@
/**
* This is set if we had to do a delayed dexopt of an app before launching
- * it, to increasing the ANR timeouts in that case.
+ * it, to increase the ANR timeouts in that case.
*/
boolean mDidDexOpt;
@@ -1323,7 +1323,7 @@
}
} break;
case UPDATE_HTTP_PROXY_MSG: {
- ProxyProperties proxy = (ProxyProperties)msg.obj;
+ ProxyInfo proxy = (ProxyInfo)msg.obj;
String host = "";
String port = "";
String exclList = "";
@@ -1331,8 +1331,8 @@
if (proxy != null) {
host = proxy.getHost();
port = Integer.toString(proxy.getPort());
- exclList = proxy.getExclusionList();
- pacFileUrl = proxy.getPacFileUrl();
+ exclList = proxy.getExclusionListAsString();
+ pacFileUrl = proxy.getPacFileUrl().toString();
}
synchronized (ActivityManagerService.this) {
for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
@@ -1850,6 +1850,12 @@
@Override
public boolean onPackageChanged(String packageName, int uid, String[] components) {
+ onPackageModified(packageName);
+ return true;
+ }
+
+ @Override
+ public void onPackageModified(String packageName) {
final PackageManager pm = mContext.getPackageManager();
final ArrayList<Pair<Intent, Integer>> recentTaskIntents =
new ArrayList<Pair<Intent, Integer>>();
@@ -1885,7 +1891,6 @@
removeTaskByIdLocked(tasksToRemove.get(i), 0);
}
}
- return true;
}
@Override
@@ -13758,7 +13763,7 @@
}
if (Proxy.PROXY_CHANGE_ACTION.equals(intent.getAction())) {
- ProxyProperties proxy = intent.getParcelableExtra("proxy");
+ ProxyInfo proxy = intent.getParcelableExtra("proxy");
mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
}
@@ -16523,7 +16528,7 @@
}
if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
- if (userId != 0) {
+ if (userId != UserHandle.USER_OWNER) {
Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntentLocked(null, null, intent, null,
@@ -16552,6 +16557,8 @@
EventLogTags.writeAmSwitchUser(userId);
getUserManagerLocked().userForeground(userId);
sendUserSwitchBroadcastsLocked(oldUserId, userId);
+ } else {
+ mStackSupervisor.startBackgroundUserLocked(userId, uss);
}
if (needStart) {
@@ -16727,7 +16734,7 @@
}
}
- void finishUserSwitch(UserStartedState uss) {
+ void finishUserBoot(UserStartedState uss) {
synchronized (this) {
if (uss.mState == UserStartedState.STATE_BOOTING
&& mStartedUsers.get(uss.mHandle.getIdentifier()) == uss) {
@@ -16741,6 +16748,12 @@
android.Manifest.permission.RECEIVE_BOOT_COMPLETED, AppOpsManager.OP_NONE,
true, false, MY_PID, Process.SYSTEM_UID, userId);
}
+ }
+ }
+
+ void finishUserSwitch(UserStartedState uss) {
+ synchronized (this) {
+ finishUserBoot(uss);
startProfilesLocked();
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 7c3f288..efd2b57 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -17,7 +17,6 @@
package com.android.server.am;
import android.os.Trace;
-import com.android.internal.R.styleable;
import com.android.internal.app.ResolverActivity;
import com.android.server.AttributeCache;
import com.android.server.am.ActivityStack.ActivityState;
@@ -480,7 +479,7 @@
void setTask(TaskRecord newTask, ThumbnailHolder newThumbHolder, boolean isRoot) {
if (task != null && task.removeActivity(this)) {
if (task != newTask) {
- task.stack.removeTask(task, false);
+ task.stack.removeTask(task);
} 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 ee39b67..442da31 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -36,8 +36,6 @@
import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.CONTAINER_STATE_HAS_SURFACE;
-
import android.service.voice.IVoiceInteractionSession;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.BatteryStatsImpl;
@@ -1082,20 +1080,6 @@
}
}
- /**
- * Version of ensureActivitiesVisible that can easily be called anywhere.
- */
- final boolean ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
- return ensureActivitiesVisibleLocked(starting, configChanges, false);
- }
-
- final boolean ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
- boolean forceHomeShown) {
- ActivityRecord r = topRunningActivityLocked(null);
- return r != null &&
- ensureActivitiesVisibleLocked(r, starting, null, configChanges, forceHomeShown);
- }
-
// Checks if any of the stacks above this one has a fullscreen activity behind it.
// If so, this stack is hidden, otherwise it is visible.
private boolean isStackVisible() {
@@ -1107,16 +1091,26 @@
return true;
}
- // Start at the task above this one and go up, looking for a visible
- // fullscreen activity, or a translucent activity that requested the
- // wallpaper to be shown behind it.
+ /**
+ * Start at the task above this one and go up, looking for a visible
+ * fullscreen activity, or a translucent activity that requested the
+ * wallpaper to be shown behind it.
+ */
for (int i = mStacks.indexOf(this) + 1; i < mStacks.size(); i++) {
final ArrayList<TaskRecord> tasks = mStacks.get(i).getAllTasks();
for (int taskNdx = 0; taskNdx < tasks.size(); taskNdx++) {
final ArrayList<ActivityRecord> activities = tasks.get(taskNdx).mActivities;
for (int activityNdx = 0; activityNdx < activities.size(); activityNdx++) {
final ActivityRecord r = activities.get(activityNdx);
- if (!r.finishing && r.visible && r.fullscreen) {
+
+ // Conditions for an activity to obscure the stack we're
+ // examining:
+ // 1. Not Finishing AND Visible AND:
+ // 2. Either:
+ // - Full Screen Activity OR
+ // - On top of Home and our stack is NOT home
+ if (!r.finishing && r.visible && (r.fullscreen ||
+ (!isHomeStack() && r.frontOfTask && tasks.get(taskNdx).mOnTopOfHome))) {
return false;
}
}
@@ -1126,12 +1120,19 @@
return true;
}
+ final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
+ ActivityRecord r = topRunningActivityLocked(null);
+ if (r != null) {
+ ensureActivitiesVisibleLocked(r, starting, null, configChanges);
+ }
+ }
+
/**
* Make sure that all activities that need to be visible (that is, they
* currently can be seen by the user) actually are.
*/
- final boolean ensureActivitiesVisibleLocked(ActivityRecord top, ActivityRecord starting,
- String onlyThisProcess, int configChanges, boolean forceHomeShown) {
+ final void ensureActivitiesVisibleLocked(ActivityRecord top, ActivityRecord starting,
+ String onlyThisProcess, int configChanges) {
if (DEBUG_VISBILITY) Slog.v(
TAG, "ensureActivitiesVisible behind " + top
+ " configChanges=0x" + Integer.toHexString(configChanges));
@@ -1149,7 +1150,6 @@
// If the top activity is not fullscreen, then we need to
// make sure any activities under it are now visible.
boolean aboveTop = true;
- boolean showHomeBehindStack = false;
boolean behindFullscreen = !isStackVisible();
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
@@ -1237,11 +1237,9 @@
// At this point, nothing else needs to be shown
if (DEBUG_VISBILITY) Slog.v(TAG, "Fullscreen: at " + r);
behindFullscreen = true;
- showHomeBehindStack = false;
- } else if (isActivityOverHome(r)) {
+ } else if (!isHomeStack() && r.frontOfTask && task.mOnTopOfHome) {
if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
- showHomeBehindStack = true;
- behindFullscreen = !isHomeStack() && r.frontOfTask && task.mOnTopOfHome;
+ behindFullscreen = true;
}
} else {
if (DEBUG_VISBILITY) Slog.v(
@@ -1291,7 +1289,6 @@
}
}
}
- return showHomeBehindStack;
}
void convertToTranslucent(ActivityRecord r) {
@@ -2841,7 +2838,7 @@
if (mStackSupervisor.isFrontStack(this) && task == topTask() && task.mOnTopOfHome) {
mStackSupervisor.moveHomeToTop();
}
- removeTask(task, false);
+ removeTask(task);
}
cleanUpActivityServicesLocked(r);
r.removeUriPermissionsLocked();
@@ -3717,7 +3714,7 @@
return starting;
}
- void removeTask(TaskRecord task, boolean moving) {
+ void removeTask(TaskRecord task) {
mStackSupervisor.endLockTaskModeIfTaskEnding(task);
mWindowManager.removeTask(task.taskId);
final ActivityRecord r = mResumedActivity;
@@ -3731,14 +3728,20 @@
mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;
}
mTaskHistory.remove(task);
- 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) {
+
+ if (task.mActivities.isEmpty()) {
+ final boolean isVoiceSession = task.voiceSession != null;
+ if (isVoiceSession) {
+ try {
+ task.voiceSession.taskFinished(task.intent, task.taskId);
+ } catch (RemoteException e) {
+ }
}
- mService.mRecentTasks.remove(task);
+ if (task.autoRemoveFromRecents() || isVoiceSession) {
+ // Task creator asked to remove this when done, or this task was a voice
+ // interaction, so it should not remain on the recent tasks list.
+ mService.mRecentTasks.remove(task);
+ }
}
if (mTaskHistory.isEmpty()) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 2e979d2..ce3d853 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -193,6 +193,9 @@
/** Used on user changes */
final ArrayList<UserStartedState> mStartingUsers = new ArrayList<UserStartedState>();
+ /** Used to queue up any background users being started */
+ final ArrayList<UserStartedState> mStartingBackgroundUsers = new ArrayList<UserStartedState>();
+
/** Set to indicate whether to issue an onUserLeaving callback when a newly launched activity
* is being brought in front of us. */
boolean mUserLeaving = false;
@@ -1471,6 +1474,17 @@
}
}
+ switch (r.info.documentLaunchMode) {
+ case ActivityInfo.DOCUMENT_LAUNCH_NONE:
+ break;
+ case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
+ intent.addFlags(
+ Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ break;
+ case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+ break;
+ }
final boolean newDocument = intent.isDocument();
if (sourceRecord == null) {
// This activity is not being started from another... in this
@@ -1988,9 +2002,20 @@
if (booting) {
mService.finishBooting();
- } else if (startingUsers != null) {
- for (int i = 0; i < startingUsers.size(); i++) {
- mService.finishUserSwitch(startingUsers.get(i));
+ } else {
+ // Complete user switch
+ if (startingUsers != null) {
+ for (int i = 0; i < startingUsers.size(); i++) {
+ mService.finishUserSwitch(startingUsers.get(i));
+ }
+ }
+ // Complete starting up of background users
+ if (mStartingBackgroundUsers.size() > 0) {
+ startingUsers = new ArrayList<UserStartedState>(mStartingBackgroundUsers);
+ mStartingBackgroundUsers.clear();
+ for (int i = 0; i < startingUsers.size(); i++) {
+ mService.finishUserBoot(startingUsers.get(i));
+ }
}
}
@@ -2237,7 +2262,7 @@
Slog.w(TAG, "moveTaskToStack: no stack for id=" + stackId);
return;
}
- task.stack.removeTask(task, true);
+ task.stack.removeTask(task);
stack.addTask(task, toTop, true);
mWindowManager.addTask(taskId, stackId, toTop);
resumeTopActivitiesLocked();
@@ -2430,21 +2455,12 @@
void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
// First the front stacks. In case any are not fullscreen and are in front of home.
- boolean showHomeBehindStack = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
final int topStackNdx = stacks.size() - 1;
for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
- if (stackNdx == topStackNdx) {
- // Top stack.
- showHomeBehindStack =
- stack.ensureActivitiesVisibleLocked(starting, configChanges);
- } else {
- // Back stack.
- stack.ensureActivitiesVisibleLocked(starting, configChanges,
- showHomeBehindStack);
- }
+ stack.ensureActivitiesVisibleLocked(starting, configChanges);
}
}
}
@@ -2496,6 +2512,15 @@
return homeInFront;
}
+ /**
+ * Add background users to send boot completed events to.
+ * @param userId The user being started in the background
+ * @param uss The state object for the user.
+ */
+ public void startBackgroundUserLocked(int userId, UserStartedState uss) {
+ mStartingBackgroundUsers.add(uss);
+ }
+
final ArrayList<ActivityRecord> processStoppingActivitiesLocked(boolean remove) {
int N = mStoppingActivities.size();
if (N <= 0) return null;
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 9f0bc10..862932c 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -139,6 +139,9 @@
userId = UserHandle.getUserId(info.applicationInfo.uid);
creatorUid = info.applicationInfo.uid;
+ if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
+ intent.addFlags(Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
+ }
}
void disposeThumbnail() {
@@ -246,6 +249,11 @@
return mActivities.size() == 0;
}
+ boolean autoRemoveFromRecents() {
+ return intent != null &&
+ (intent.getFlags() & Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS) != 0;
+ }
+
/**
* Completely remove all activities associated with an existing
* task starting at a specified index.
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 8815d0f..0749f24 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -24,7 +24,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -157,14 +157,14 @@
* @param proxy Proxy information that is about to be broadcast.
* @return Returns true when the broadcast should not be sent
*/
- public synchronized boolean setCurrentProxyScriptUrl(ProxyProperties proxy) {
- if (!TextUtils.isEmpty(proxy.getPacFileUrl())) {
+ public synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
+ if (proxy.getPacFileUrl() != null) {
if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) {
// Allow to send broadcast, nothing to do.
return false;
}
synchronized (mProxyLock) {
- mPacUrl = proxy.getPacFileUrl();
+ mPacUrl = proxy.getPacFileUrl().toString();
}
mCurrentDelay = DELAY_1;
mHasSentBroadcast = false;
@@ -268,7 +268,7 @@
// Already bound no need to bind again.
if ((mProxyConnection != null) && (mConnection != null)) {
if (mLastPort != -1) {
- sendPacBroadcast(new ProxyProperties(mPacUrl, mLastPort));
+ sendPacBroadcast(new ProxyInfo(mPacUrl, mLastPort));
} else {
Log.e(TAG, "Received invalid port from Local Proxy,"
+ " PAC will not be operational");
@@ -362,7 +362,7 @@
mLastPort = -1;
}
- private void sendPacBroadcast(ProxyProperties proxy) {
+ private void sendPacBroadcast(ProxyInfo proxy) {
mConnectivityHandler.sendMessage(mConnectivityHandler.obtainMessage(mProxyMessage, proxy));
}
@@ -371,7 +371,7 @@
return;
}
if (!mHasSentBroadcast) {
- sendPacBroadcast(new ProxyProperties(mPacUrl, mLastPort));
+ sendPacBroadcast(new ProxyInfo(mPacUrl, mLastPort));
mHasSentBroadcast = true;
}
}
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index fd2f8a1..8968da3 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -642,8 +642,9 @@
try {
synchronized (mMcuHal) {
if (mReleased) {
- throw new IllegalStateException("This operation cannot be performed "
- + "because the dream has ended.");
+ Slog.w(TAG, "Ignoring message to MCU HAL because the dream "
+ + "has already ended: " + msg);
+ return null;
}
return mMcuHal.sendMessage(msg, arg);
}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 3dc17fc..015032b 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -17,6 +17,7 @@
package com.android.server.media;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.media.routeprovider.RouteRequest;
import android.media.session.ISessionController;
import android.media.session.ISessionControllerCallback;
@@ -59,6 +60,24 @@
public class MediaSessionRecord implements IBinder.DeathRecipient {
private static final String TAG = "MediaSessionRecord";
+ /**
+ * These are the playback states that count as currently active.
+ */
+ private static final int[] ACTIVE_STATES = {
+ PlaybackState.PLAYSTATE_FAST_FORWARDING,
+ PlaybackState.PLAYSTATE_REWINDING,
+ PlaybackState.PLAYSTATE_SKIPPING_BACKWARDS,
+ PlaybackState.PLAYSTATE_SKIPPING_FORWARDS,
+ PlaybackState.PLAYSTATE_BUFFERING,
+ PlaybackState.PLAYSTATE_CONNECTING,
+ PlaybackState.PLAYSTATE_PLAYING };
+
+ /**
+ * The length of time a session will still be considered active after
+ * pausing in ms.
+ */
+ private static final int ACTIVE_BUFFER = 30000;
+
private final MessageHandler mHandler;
private final int mPid;
@@ -74,21 +93,22 @@
new ArrayList<ISessionControllerCallback>();
private final ArrayList<RouteRequest> mRequests = new ArrayList<RouteRequest>();
- private boolean mTransportPerformerEnabled = false;
private RouteInfo mRoute;
private RouteOptions mRequest;
private RouteConnectionRecord mConnection;
// TODO define a RouteState class with relevant info
private int mRouteState;
+ private long mFlags;
// TransportPerformer fields
private MediaMetadata mMetadata;
private PlaybackState mPlaybackState;
private int mRatingType;
+ private long mLastActiveTime;
// End TransportPerformer fields
- private boolean mIsPublished = false;
+ private boolean mIsActive = false;
public MediaSessionRecord(int pid, String packageName, ISessionCallback cb, String tag,
MediaSessionService service, Handler handler) {
@@ -148,6 +168,35 @@
}
/**
+ * Get this session's flags.
+ *
+ * @return The flags for this session.
+ */
+ public long getFlags() {
+ return mFlags;
+ }
+
+ /**
+ * Check if this session has the specified flag.
+ *
+ * @param flag The flag to check.
+ * @return True if this session has that flag set, false otherwise.
+ */
+ public boolean hasFlag(int flag) {
+ return (mFlags & flag) != 0;
+ }
+
+ /**
+ * Check if this session has system priorty and should receive media buttons
+ * before any other sessions.
+ *
+ * @return True if this is a system priority session, false otherwise
+ */
+ public boolean isSystemPriority() {
+ return (mFlags & Session.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0;
+ }
+
+ /**
* Set the selected route. This does not connect to the route, just notifies
* the app that a new route has been selected.
*
@@ -215,12 +264,36 @@
}
/**
- * Check if this session has been published by the app yet.
+ * Check if this session has been set to active by the app.
*
- * @return True if it has been published, false otherwise.
+ * @return True if the session is active, false otherwise.
*/
- public boolean isPublished() {
- return mIsPublished;
+ public boolean isActive() {
+ return mIsActive;
+ }
+
+ /**
+ * Check if the session is currently performing playback. This will also
+ * return true if the session was recently paused.
+ *
+ * @return True if the session is performing playback, false otherwise.
+ */
+ public boolean isPlaybackActive() {
+ int state = mPlaybackState == null ? 0 : mPlaybackState.getState();
+ if (isActiveState(state)) {
+ return true;
+ }
+ if (state == mPlaybackState.PLAYSTATE_PAUSED) {
+ long inactiveTime = SystemClock.uptimeMillis() - mLastActiveTime;
+ if (inactiveTime < ACTIVE_BUFFER) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isTransportControlEnabled() {
+ return hasFlag(Session.FLAG_HANDLES_TRANSPORT_CONTROLS);
}
@Override
@@ -234,11 +307,11 @@
final String indent = prefix + " ";
pw.println(indent + "pid=" + mPid);
pw.println(indent + "info=" + mSessionInfo.toString());
- pw.println(indent + "published=" + mIsPublished);
- pw.println(indent + "transport controls enabled=" + mTransportPerformerEnabled);
+ pw.println(indent + "published=" + mIsActive);
+ pw.println(indent + "flags=" + mFlags);
pw.println(indent + "rating type=" + mRatingType);
pw.println(indent + "controllers: " + mControllerCallbacks.size());
- pw.println(indent + "state=" + mPlaybackState.toString());
+ pw.println(indent + "state=" + (mPlaybackState == null ? null : mPlaybackState.toString()));
pw.println(indent + "metadata:" + getShortMetadataString());
pw.println(indent + "route requests {");
int size = mRequests.size();
@@ -251,6 +324,15 @@
pw.println(indent + "params=" + (mRequest == null ? null : mRequest.toString()));
}
+ private boolean isActiveState(int state) {
+ for (int i = 0; i < ACTIVE_STATES.length; i++) {
+ if (ACTIVE_STATES[i] == state) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private String getShortMetadataString() {
int fields = mMetadata == null ? 0 : mMetadata.size();
String title = mMetadata == null ? null : mMetadata
@@ -393,12 +475,21 @@
}
@Override
- public void publish() {
- mIsPublished = true; // TODO push update to service
+ public void setActive(boolean active) {
+ mIsActive = active;
+ mService.updateSession(MediaSessionRecord.this);
+ mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE);
}
+
@Override
- public void setTransportPerformerEnabled() {
- mTransportPerformerEnabled = true;
+ public void setFlags(int flags) {
+ if ((flags & Session.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
+ int pid = getCallingPid();
+ int uid = getCallingUid();
+ mService.enforcePhoneStatePermission(pid, uid);
+ }
+ mFlags = flags;
+ mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE);
}
@Override
@@ -409,7 +500,13 @@
@Override
public void setPlaybackState(PlaybackState state) {
+ int oldState = mPlaybackState == null ? 0 : mPlaybackState.getState();
+ int newState = state == null ? 0 : state.getState();
+ if (isActiveState(oldState) && newState == PlaybackState.PLAYSTATE_PAUSED) {
+ mLastActiveTime = SystemClock.elapsedRealtime();
+ }
mPlaybackState = state;
+ mService.onSessionPlaystateChange(MediaSessionRecord.this, oldState, newState);
mHandler.post(MessageHandler.MSG_UPDATE_PLAYBACK_STATE);
}
@@ -673,7 +770,7 @@
@Override
public boolean isTransportControlEnabled() {
- return mTransportPerformerEnabled;
+ return MediaSessionRecord.this.isTransportControlEnabled();
}
@Override
@@ -689,6 +786,7 @@
private static final int MSG_SEND_EVENT = 4;
private static final int MSG_UPDATE_ROUTE_FILTERS = 5;
private static final int MSG_SEND_COMMAND = 6;
+ private static final int MSG_UPDATE_SESSION_STATE = 7;
public MessageHandler(Looper looper) {
super(looper);
@@ -713,6 +811,9 @@
(Pair<RouteCommand, ResultReceiver>) msg.obj;
pushRouteCommand(cmd.first, cmd.second);
break;
+ case MSG_UPDATE_SESSION_STATE:
+ // TODO add session state
+ break;
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 107f6ad..fb858fc 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -17,17 +17,25 @@
package com.android.server.media;
import android.Manifest;
+import android.app.ActivityManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.media.routeprovider.RouteRequest;
import android.media.session.ISession;
import android.media.session.ISessionCallback;
+import android.media.session.ISessionController;
import android.media.session.ISessionManager;
+import android.media.session.PlaybackState;
import android.media.session.RouteInfo;
import android.media.session.RouteOptions;
import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
@@ -38,6 +46,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.List;
/**
* System implementation of MediaSessionManager
@@ -48,15 +57,17 @@
private final SessionManagerImpl mSessionManagerImpl;
private final MediaRouteProviderWatcher mRouteProviderWatcher;
+ private final MediaSessionStack mPriorityStack;
- private final ArrayList<MediaSessionRecord> mSessions
- = new ArrayList<MediaSessionRecord>();
+ private final ArrayList<MediaSessionRecord> mRecords = new ArrayList<MediaSessionRecord>();
private final ArrayList<MediaRouteProviderProxy> mProviders
= new ArrayList<MediaRouteProviderProxy>();
private final Object mLock = new Object();
// TODO do we want a separate thread for handling mediasession messages?
private final Handler mHandler = new Handler();
+ private MediaSessionRecord mPrioritySession;
+
// Used to keep track of the current request to show routes for a specific
// session so we drop late callbacks properly.
private int mShowRoutesRequestId = 0;
@@ -69,6 +80,7 @@
mSessionManagerImpl = new SessionManagerImpl();
mRouteProviderWatcher = new MediaRouteProviderWatcher(context, mProviderWatcherCallback,
mHandler, context.getUserId());
+ mPriorityStack = new MediaSessionStack();
}
@Override
@@ -121,6 +133,30 @@
}
}
+ public void updateSession(MediaSessionRecord record) {
+ synchronized (mLock) {
+ mPriorityStack.onSessionStateChange(record);
+ if (record.isSystemPriority()) {
+ if (record.isActive()) {
+ if (mPrioritySession != null) {
+ Log.w(TAG, "Replacing existing priority session with a new session");
+ }
+ mPrioritySession = record;
+ } else {
+ if (mPrioritySession == record) {
+ mPrioritySession = null;
+ }
+ }
+ }
+ }
+ }
+
+ public void onSessionPlaystateChange(MediaSessionRecord record, int oldState, int newState) {
+ synchronized (mLock) {
+ mPriorityStack.onPlaystateChange(record, oldState, newState);
+ }
+ }
+
@Override
public void monitor() {
synchronized (mLock) {
@@ -141,7 +177,11 @@
}
private void destroySessionLocked(MediaSessionRecord session) {
- mSessions.remove(session);
+ mRecords.remove(session);
+ mPriorityStack.removeSession(session);
+ if (session == mPrioritySession) {
+ mPrioritySession = null;
+ }
}
private void enforcePackageName(String packageName, int uid) {
@@ -158,8 +198,64 @@
throw new IllegalArgumentException("packageName is not owned by the calling process");
}
+ protected void enforcePhoneStatePermission(int pid, int uid) {
+ if (getContext().checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, pid, uid)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold the MODIFY_PHONE_STATE permission.");
+ }
+ }
+
+ /**
+ * Checks a caller's authorization to register an IRemoteControlDisplay.
+ * Authorization is granted if one of the following is true:
+ * <ul>
+ * <li>the caller has android.Manifest.permission.MEDIA_CONTENT_CONTROL
+ * permission</li>
+ * <li>the caller's listener is one of the enabled notification listeners</li>
+ * </ul>
+ */
+ private void enforceMediaPermissions(ComponentName compName, int pid, int uid) {
+ if (getContext()
+ .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
+ != PackageManager.PERMISSION_GRANTED
+ && !isEnabledNotificationListener(compName)) {
+ throw new SecurityException("Missing permission to control media.");
+ }
+ }
+
+ private boolean isEnabledNotificationListener(ComponentName compName) {
+ if (compName != null) {
+ final int currentUser = ActivityManager.getCurrentUser();
+ final String enabledNotifListeners = Settings.Secure.getStringForUser(
+ getContext().getContentResolver(),
+ Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+ currentUser);
+ if (enabledNotifListeners != null) {
+ final String[] components = enabledNotifListeners.split(":");
+ for (int i = 0; i < components.length; i++) {
+ final ComponentName component =
+ ComponentName.unflattenFromString(components[i]);
+ if (component != null) {
+ if (compName.equals(component)) {
+ if (DEBUG) {
+ Log.d(TAG, "ok to get sessions: " + component +
+ " is authorized notification listener");
+ }
+ return true;
+ }
+ }
+ }
+ }
+ if (DEBUG) {
+ Log.d(TAG, "not ok to get sessions, " + compName +
+ " is not in list of ENABLED_NOTIFICATION_LISTENERS");
+ }
+ }
+ return false;
+ }
+
private MediaSessionRecord createSessionInternal(int pid, String packageName,
- ISessionCallback cb, String tag) {
+ ISessionCallback cb, String tag, boolean forCalls) {
synchronized (mLock) {
return createSessionLocked(pid, packageName, cb, tag);
}
@@ -174,13 +270,24 @@
} catch (RemoteException e) {
throw new RuntimeException("Media Session owner died prematurely.", e);
}
- mSessions.add(session);
+ mRecords.add(session);
+ mPriorityStack.addSession(session);
if (DEBUG) {
Log.d(TAG, "Created session for package " + packageName + " with tag " + tag);
}
return session;
}
+ private int findIndexOfSessionForIdLocked(String sessionId) {
+ for (int i = mRecords.size() - 1; i >= 0; i--) {
+ MediaSessionRecord session = mRecords.get(i);
+ if (TextUtils.equals(session.getSessionInfo().getId(), sessionId)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
private MediaRouteProviderProxy getProviderLocked(String providerId) {
for (int i = mProviders.size() - 1; i >= 0; i--) {
MediaRouteProviderProxy provider = mProviders.get(i);
@@ -191,14 +298,9 @@
return null;
}
- private int findIndexOfSessionForIdLocked(String sessionId) {
- for (int i = mSessions.size() - 1; i >= 0; i--) {
- MediaSessionRecord session = mSessions.get(i);
- if (TextUtils.equals(session.getSessionInfo().getId(), sessionId)) {
- return i;
- }
- }
- return -1;
+ private boolean isSessionDiscoverable(MediaSessionRecord record) {
+ // TODO probably want to check more than if it's published.
+ return record.isActive();
}
private MediaRouteProviderWatcher.Callback mProviderWatcherCallback
@@ -232,7 +334,7 @@
synchronized (mLock) {
int index = findIndexOfSessionForIdLocked(sessionId);
if (index != -1 && routes != null && routes.size() > 0) {
- MediaSessionRecord record = mSessions.get(index);
+ MediaSessionRecord record = mRecords.get(index);
record.selectRoute(routes.get(0));
}
}
@@ -244,7 +346,7 @@
synchronized (mLock) {
int index = findIndexOfSessionForIdLocked(sessionId);
if (index != -1) {
- MediaSessionRecord session = mSessions.get(index);
+ MediaSessionRecord session = mRecords.get(index);
session.setRouteConnected(route, options.getConnectionOptions(), connection);
}
}
@@ -266,7 +368,37 @@
if (cb == null) {
throw new IllegalArgumentException("Controller callback cannot be null");
}
- return createSessionInternal(pid, packageName, cb, tag).getSessionBinder();
+ return createSessionInternal(pid, packageName, cb, tag, false).getSessionBinder();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public List<IBinder> getSessions(ComponentName componentName) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+
+ try {
+ if (componentName != null) {
+ // If they gave us a component name verify they own the
+ // package
+ enforcePackageName(componentName.getPackageName(), uid);
+ }
+ // Then check if they have the permissions or their component is
+ // allowed
+ enforceMediaPermissions(componentName, pid, uid);
+ ArrayList<IBinder> binders = new ArrayList<IBinder>();
+ synchronized (mLock) {
+ ArrayList<MediaSessionRecord> records = mPriorityStack
+ .getActiveSessions();
+ int size = records.size();
+ for (int i = 0; i < size; i++) {
+ binders.add(records.get(i).getControllerBinder().asBinder());
+ }
+ }
+ return binders;
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -286,13 +418,18 @@
pw.println();
synchronized (mLock) {
- int count = mSessions.size();
- pw.println("Sessions - have " + count + " states:");
- for (int i = 0; i < count; i++) {
- MediaSessionRecord record = mSessions.get(i);
- pw.println();
- record.dump(pw, "");
+ pw.println("Session for calls:" + mPrioritySession);
+ if (mPrioritySession != null) {
+ mPrioritySession.dump(pw, "");
}
+ int count = mRecords.size();
+ pw.println(count + " Sessions:");
+ for (int i = 0; i < count; i++) {
+ mRecords.get(i).dump(pw, "");
+ pw.println();
+ }
+ mPriorityStack.dumpLocked(pw, "");
+
pw.println("Providers:");
count = mProviders.size();
for (int i = 0; i < count; i++) {
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
new file mode 100644
index 0000000..f9f004d
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media;
+
+import android.media.session.PlaybackState;
+import android.media.session.Session;
+import android.text.TextUtils;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Keeps track of media sessions and their priority for notifications, media
+ * button routing, etc.
+ */
+public class MediaSessionStack {
+ /**
+ * These are states that usually indicate the user took an action and should
+ * bump priority regardless of the old state.
+ */
+ private static final int[] ALWAYS_PRIORITY_STATES = {
+ PlaybackState.PLAYSTATE_FAST_FORWARDING,
+ PlaybackState.PLAYSTATE_REWINDING,
+ PlaybackState.PLAYSTATE_SKIPPING_BACKWARDS,
+ PlaybackState.PLAYSTATE_SKIPPING_FORWARDS };
+ /**
+ * These are states that usually indicate the user took an action if they
+ * were entered from a non-priority state.
+ */
+ private static final int[] TRANSITION_PRIORITY_STATES = {
+ PlaybackState.PLAYSTATE_BUFFERING,
+ PlaybackState.PLAYSTATE_CONNECTING,
+ PlaybackState.PLAYSTATE_PLAYING };
+
+ private final ArrayList<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>();
+
+ private MediaSessionRecord mCachedButtonReceiver;
+ private MediaSessionRecord mCachedDefault;
+ private ArrayList<MediaSessionRecord> mCachedActiveList;
+ private ArrayList<MediaSessionRecord> mCachedTransportControlList;
+
+ /**
+ * Add a record to the priority tracker.
+ *
+ * @param record The record to add.
+ */
+ public void addSession(MediaSessionRecord record) {
+ mSessions.add(record);
+ clearCache();
+ }
+
+ /**
+ * Remove a record from the priority tracker.
+ *
+ * @param record The record to remove.
+ */
+ public void removeSession(MediaSessionRecord record) {
+ mSessions.remove(record);
+ clearCache();
+ }
+
+ /**
+ * Notify the priority tracker that a session's state changed.
+ *
+ * @param record The record that changed.
+ * @param oldState Its old playback state.
+ * @param newState Its new playback state.
+ */
+ public void onPlaystateChange(MediaSessionRecord record, int oldState, int newState) {
+ if (shouldUpdatePriority(oldState, newState)) {
+ mSessions.remove(record);
+ mSessions.add(0, record);
+ clearCache();
+ }
+ }
+
+ /**
+ * Handle any stack changes that need to occur in response to a session
+ * state change. TODO add the old and new session state as params
+ *
+ * @param record The record that changed.
+ */
+ public void onSessionStateChange(MediaSessionRecord record) {
+ // For now just clear the cache. Eventually we'll selectively clear
+ // depending on what changed.
+ clearCache();
+ }
+
+ /**
+ * Get the current priority sorted list of active sessions. The most
+ * important session is at index 0 and the least important at size - 1.
+ *
+ * @return All the active sessions in priority order.
+ */
+ public ArrayList<MediaSessionRecord> getActiveSessions() {
+ if (mCachedActiveList == null) {
+ mCachedActiveList = getPriorityListLocked(true, 0);
+ }
+ return mCachedActiveList;
+ }
+
+ /**
+ * Get the current priority sorted list of active sessions that use
+ * transport controls. The most important session is at index 0 and the
+ * least important at size -1.
+ *
+ * @return All the active sessions that handle transport controls in
+ * priority order.
+ */
+ public ArrayList<MediaSessionRecord> getTransportControlSessions() {
+ if (mCachedTransportControlList == null) {
+ mCachedTransportControlList = getPriorityListLocked(true,
+ Session.FLAG_HANDLES_TRANSPORT_CONTROLS);
+ }
+ return mCachedTransportControlList;
+ }
+
+ /**
+ * Get the highest priority active session.
+ *
+ * @return The current highest priority session or null.
+ */
+ public MediaSessionRecord getDefaultSession() {
+ if (mCachedDefault != null) {
+ return mCachedDefault;
+ }
+ ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, 0);
+ if (records.size() > 0) {
+ return records.get(0);
+ }
+ return null;
+ }
+
+ /**
+ * Get the highest priority session that can handle media buttons.
+ *
+ * @return The default media button session or null.
+ */
+ public MediaSessionRecord getDefaultMediaButtonSession() {
+ if (mCachedButtonReceiver != null) {
+ return mCachedButtonReceiver;
+ }
+ ArrayList<MediaSessionRecord> records = getPriorityListLocked(true,
+ Session.FLAG_HANDLES_MEDIA_BUTTONS);
+ if (records.size() > 0) {
+ mCachedButtonReceiver = records.get(0);
+ }
+ return mCachedButtonReceiver;
+ }
+
+ public void dumpLocked(PrintWriter pw, String prefix) {
+ ArrayList<MediaSessionRecord> sortedSessions = getPriorityListLocked(false, 0);
+ int count = sortedSessions.size();
+ pw.println(prefix + "Sessions Stack - have " + count + " sessions:");
+ String indent = prefix + " ";
+ for (int i = 0; i < count; i++) {
+ MediaSessionRecord record = sortedSessions.get(i);
+ record.dump(pw, indent);
+ pw.println();
+ }
+ }
+
+ /**
+ * Get a priority sorted list of sessions. Can filter to only return active
+ * sessions or sessions with specific flags.
+ *
+ * @param activeOnly True to only return active sessions, false to return
+ * all sessions.
+ * @param withFlags Only return sessions with all the specified flags set. 0
+ * returns all sessions.
+ * @return The priority sorted list of sessions.
+ */
+ private ArrayList<MediaSessionRecord> getPriorityListLocked(boolean activeOnly, int withFlags) {
+ ArrayList<MediaSessionRecord> result = new ArrayList<MediaSessionRecord>();
+ int lastLocalIndex = 0;
+ int lastActiveIndex = 0;
+ int lastPublishedIndex = 0;
+
+ int size = mSessions.size();
+ for (int i = 0; i < size; i++) {
+ final MediaSessionRecord session = mSessions.get(i);
+
+ if ((session.getFlags() & withFlags) != withFlags) {
+ continue;
+ }
+ if (!session.isActive()) {
+ if (!activeOnly) {
+ // If we're getting unpublished as well always put them at
+ // the end
+ result.add(session);
+ }
+ continue;
+ }
+
+ if (session.isSystemPriority()) {
+ // System priority sessions are special and always go at the
+ // front. We expect there to only be one of these at a time.
+ result.add(0, session);
+ lastLocalIndex++;
+ lastActiveIndex++;
+ lastPublishedIndex++;
+ } else if (session.isPlaybackActive()) {
+ // TODO replace getRoute() == null with real local route check
+ if(session.getRoute() == null) {
+ // Active local sessions get top priority
+ result.add(lastLocalIndex, session);
+ lastLocalIndex++;
+ lastActiveIndex++;
+ lastPublishedIndex++;
+ } else {
+ // Then active remote sessions
+ result.add(lastActiveIndex, session);
+ lastActiveIndex++;
+ lastPublishedIndex++;
+ }
+ } else {
+ // inactive sessions go at the end in order of whoever last did
+ // something.
+ result.add(lastPublishedIndex, session);
+ lastPublishedIndex++;
+ }
+ }
+
+ return result;
+ }
+
+ private boolean shouldUpdatePriority(int oldState, int newState) {
+ if (containsState(newState, ALWAYS_PRIORITY_STATES)) {
+ return true;
+ }
+ if (!containsState(oldState, TRANSITION_PRIORITY_STATES)
+ && containsState(newState, TRANSITION_PRIORITY_STATES)) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean containsState(int state, int[] states) {
+ for (int i = 0; i < states.length; i++) {
+ if (states[i] == state) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void clearCache() {
+ mCachedDefault = null;
+ mCachedButtonReceiver = null;
+ mCachedActiveList = null;
+ mCachedTransportControlList = null;
+ }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7aa5d79..fce86e8 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -198,8 +198,7 @@
private final UserProfiles mUserProfiles = new UserProfiles();
private NotificationListeners mListeners;
private ConditionProviders mConditionProviders;
-
- private final NotificationUsageStats mUsageStats = new NotificationUsageStats();
+ private NotificationUsageStats mUsageStats;
private static final String EXTRA_INTERCEPT = "android.intercept";
@@ -472,6 +471,7 @@
pw.println(prefix + String.format(" defaults=0x%08x flags=0x%08x",
notification.defaults, notification.flags));
pw.println(prefix + " sound=" + notification.sound);
+ pw.println(prefix + String.format(" color=0x%08x", notification.color));
pw.println(prefix + " vibrate=" + Arrays.toString(notification.vibrate));
pw.println(prefix + String.format(" led=0x%08x onMs=%d offMs=%d",
notification.ledARGB, notification.ledOnMS, notification.ledOffMS));
@@ -858,6 +858,7 @@
});
final File systemDir = new File(Environment.getDataDirectory(), "system");
mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
+ mUsageStats = new NotificationUsageStats(getContext());
importOldBlockDb();
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index d9e2b91..45ab3d3 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -18,8 +18,17 @@
import com.android.server.notification.NotificationManagerService.NotificationRecord;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
import android.os.SystemClock;
import android.service.notification.StatusBarNotification;
+import android.util.Log;
import java.io.PrintWriter;
import java.util.HashMap;
@@ -37,9 +46,13 @@
* {@hide}
*/
public class NotificationUsageStats {
-
// Guarded by synchronized(this).
private final Map<String, AggregatedStats> mStats = new HashMap<String, AggregatedStats>();
+ private final SQLiteLog mSQLiteLog;
+
+ public NotificationUsageStats(Context context) {
+ mSQLiteLog = new SQLiteLog(context);
+ }
/**
* Called when a notification has been posted.
@@ -49,6 +62,7 @@
for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
stats.numPostedByApp++;
}
+ mSQLiteLog.logPosted(notification);
}
/**
@@ -68,6 +82,7 @@
stats.numRemovedByApp++;
stats.collect(notification.stats);
}
+ mSQLiteLog.logRemoved(notification);
}
/**
@@ -79,6 +94,7 @@
stats.numDismissedByUser++;
stats.collect(notification.stats);
}
+ mSQLiteLog.logDismissed(notification);
}
/**
@@ -89,6 +105,7 @@
for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
stats.numClickedByUser++;
}
+ mSQLiteLog.logClicked(notification);
}
/**
@@ -146,6 +163,7 @@
for (AggregatedStats as : mStats.values()) {
as.dump(pw, indent);
}
+ mSQLiteLog.dump(pw, indent);
}
/**
@@ -274,4 +292,211 @@
'}';
}
}
+
+ private static class SQLiteLog {
+ private static final String TAG = "NotificationSQLiteLog";
+
+ // Message types passed to the background handler.
+ private static final int MSG_POST = 1;
+ private static final int MSG_CLICK = 2;
+ private static final int MSG_REMOVE = 3;
+ private static final int MSG_DISMISS = 4;
+
+ private static final String DB_NAME = "notification_log.db";
+ private static final int DB_VERSION = 1;
+
+ /** Age in ms after which events are pruned from the DB. */
+ private static final long HORIZON_MS = 7 * 24 * 60 * 60 * 1000L; // 1 week
+ /** Delay between pruning the DB. Used to throttle pruning. */
+ private static final long PRUNE_MIN_DELAY_MS = 6 * 60 * 60 * 1000L; // 6 hours
+ /** Mininum number of writes between pruning the DB. Used to throttle pruning. */
+ private static final long PRUNE_MIN_WRITES = 1024;
+
+ // Table 'log'
+ private static final String TAB_LOG = "log";
+ private static final String COL_EVENT_USER_ID = "event_user_id";
+ private static final String COL_EVENT_TYPE = "event_type";
+ private static final String COL_EVENT_TIME = "event_time_ms";
+ private static final String COL_KEY = "key";
+ private static final String COL_PKG = "pkg";
+ private static final String COL_NOTIFICATION_ID = "nid";
+ private static final String COL_TAG = "tag";
+ private static final String COL_WHEN_MS = "when_ms";
+ private static final String COL_DEFAULTS = "defaults";
+ private static final String COL_FLAGS = "flags";
+ private static final String COL_PRIORITY = "priority";
+ private static final String COL_CATEGORY = "category";
+ private static final String COL_ACTION_COUNT = "action_count";
+
+ private static final int EVENT_TYPE_POST = 1;
+ private static final int EVENT_TYPE_CLICK = 2;
+ private static final int EVENT_TYPE_REMOVE = 3;
+ private static final int EVENT_TYPE_DISMISS = 4;
+
+ private static long sLastPruneMs;
+ private static long sNumWrites;
+
+ private final SQLiteOpenHelper mHelper;
+ private final Handler mWriteHandler;
+
+ private static final long DAY_MS = 24 * 60 * 60 * 1000;
+
+ public SQLiteLog(Context context) {
+ HandlerThread backgroundThread = new HandlerThread("notification-sqlite-log",
+ android.os.Process.THREAD_PRIORITY_BACKGROUND);
+ backgroundThread.start();
+ mWriteHandler = new Handler(backgroundThread.getLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ NotificationRecord r = (NotificationRecord) msg.obj;
+ long nowMs = System.currentTimeMillis();
+ switch (msg.what) {
+ case MSG_POST:
+ writeEvent(r.sbn.getPostTime(), EVENT_TYPE_POST, r, true);
+ break;
+ case MSG_CLICK:
+ writeEvent(nowMs, EVENT_TYPE_CLICK, r, false);
+ break;
+ case MSG_REMOVE:
+ writeEvent(nowMs, EVENT_TYPE_REMOVE, r, false);
+ break;
+ case MSG_DISMISS:
+ writeEvent(nowMs, EVENT_TYPE_DISMISS, r, false);
+ break;
+ default:
+ Log.wtf(TAG, "Unknown message type: " + msg.what);
+ break;
+ }
+ }
+ };
+ mHelper = new SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TAB_LOG + " (" +
+ "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
+ COL_EVENT_USER_ID + " INT," +
+ COL_EVENT_TYPE + " INT," +
+ COL_EVENT_TIME + " INT," +
+ COL_KEY + " TEXT," +
+ COL_PKG + " TEXT," +
+ COL_NOTIFICATION_ID + " INT," +
+ COL_TAG + " TEXT," +
+ COL_WHEN_MS + " INT," +
+ COL_DEFAULTS + " INT," +
+ COL_FLAGS + " INT," +
+ COL_PRIORITY + " INT," +
+ COL_CATEGORY + " TEXT," +
+ COL_ACTION_COUNT + " INT" +
+ ")");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ db.execSQL("DROP TABLE IF EXISTS " + TAB_LOG);
+ onCreate(db);
+ }
+ };
+ }
+
+ public void logPosted(NotificationRecord notification) {
+ mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_POST, notification));
+ }
+
+ public void logClicked(NotificationRecord notification) {
+ mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_CLICK, notification));
+ }
+
+ public void logRemoved(NotificationRecord notification) {
+ mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_REMOVE, notification));
+ }
+
+ public void logDismissed(NotificationRecord notification) {
+ mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_DISMISS, notification));
+ }
+
+ public void printPostFrequencies(PrintWriter pw, String indent) {
+ SQLiteDatabase db = mHelper.getReadableDatabase();
+ long nowMs = System.currentTimeMillis();
+ String q = "SELECT " +
+ COL_EVENT_USER_ID + ", " +
+ COL_PKG + ", " +
+ // Bucket by day by looking at 'floor((nowMs - eventTimeMs) / dayMs)'
+ "CAST(((" + nowMs + " - " + COL_EVENT_TIME + ") / " + DAY_MS + ") AS int) " +
+ "AS day, " +
+ "COUNT(*) AS cnt " +
+ "FROM " + TAB_LOG + " " +
+ "WHERE " +
+ COL_EVENT_TYPE + "=" + EVENT_TYPE_POST + " " +
+ "GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG;
+ Cursor cursor = db.rawQuery(q, null);
+ try {
+ for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
+ int userId = cursor.getInt(0);
+ String pkg = cursor.getString(1);
+ int day = cursor.getInt(2);
+ int count = cursor.getInt(3);
+ pw.println(indent + "post_frequency{user_id=" + userId + ",pkg=" + pkg +
+ ",day=" + day + ",count=" + count + "}");
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+
+ private void writeEvent(long eventTimeMs, int eventType, NotificationRecord r,
+ boolean populateNotificationDetails) {
+ ContentValues cv = new ContentValues();
+ cv.put(COL_EVENT_USER_ID, r.sbn.getUser().getIdentifier());
+ cv.put(COL_EVENT_TIME, eventTimeMs);
+ cv.put(COL_EVENT_TYPE, eventType);
+ putNotificationIdentifiers(r, cv);
+ if (populateNotificationDetails) {
+ putNotificationDetails(r, cv);
+ }
+ SQLiteDatabase db = mHelper.getWritableDatabase();
+ if (db.insert(TAB_LOG, null, cv) < 0) {
+ Log.wtf(TAG, "Error while trying to insert values: " + cv);
+ }
+ sNumWrites++;
+ pruneIfNecessary(db);
+ }
+
+ private void pruneIfNecessary(SQLiteDatabase db) {
+ // Prune if we haven't in a while.
+ long nowMs = System.currentTimeMillis();
+ if (sNumWrites > PRUNE_MIN_WRITES ||
+ nowMs - sLastPruneMs > PRUNE_MIN_DELAY_MS) {
+ sNumWrites = 0;
+ sLastPruneMs = nowMs;
+ long horizonStartMs = nowMs - HORIZON_MS;
+ int deletedRows = db.delete(TAB_LOG, COL_EVENT_TIME + " < ?",
+ new String[] { String.valueOf(horizonStartMs) });
+ Log.d(TAG, "Pruned event entries: " + deletedRows);
+ }
+ }
+
+ private static void putNotificationIdentifiers(NotificationRecord r, ContentValues outCv) {
+ outCv.put(COL_KEY, r.sbn.getKey());
+ outCv.put(COL_PKG, r.sbn.getPackageName());
+ }
+
+ private static void putNotificationDetails(NotificationRecord r, ContentValues outCv) {
+ outCv.put(COL_NOTIFICATION_ID, r.sbn.getId());
+ if (r.sbn.getTag() != null) {
+ outCv.put(COL_TAG, r.sbn.getTag());
+ }
+ outCv.put(COL_WHEN_MS, r.sbn.getPostTime());
+ outCv.put(COL_FLAGS, r.getNotification().flags);
+ outCv.put(COL_PRIORITY, r.getNotification().priority);
+ if (r.getNotification().category != null) {
+ outCv.put(COL_CATEGORY, r.getNotification().category);
+ }
+ outCv.put(COL_ACTION_COUNT, r.getNotification().actions != null ?
+ r.getNotification().actions.length : 0);
+ }
+
+ public void dump(PrintWriter pw, String indent) {
+ printPostFrequencies(pw, indent);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
new file mode 100644
index 0000000..f2db791
--- /dev/null
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Log;
+
+import java.util.HashSet;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * {@hide}
+ */
+public class BackgroundDexOptService {
+
+ static final String TAG = "BackgroundDexOptService";
+
+ private final BroadcastReceiver mIdleMaintenanceReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)) {
+ onIdleStart();
+ } else if (Intent.ACTION_IDLE_MAINTENANCE_END.equals(action)) {
+ onIdleStop();
+ }
+ }
+ };
+
+ final PackageManagerService mPackageManager;
+
+ final AtomicBoolean mIdleTime = new AtomicBoolean(false);
+
+ public BackgroundDexOptService(Context context) {
+ mPackageManager = (PackageManagerService)ServiceManager.getService("package");
+
+ IntentFilter idleMaintenanceFilter = new IntentFilter();
+ idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_START);
+ idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_END);
+ context.registerReceiverAsUser(mIdleMaintenanceReceiver, UserHandle.ALL,
+ idleMaintenanceFilter, null, null);
+ }
+
+ public boolean onIdleStart() {
+ Log.i(TAG, "onIdleStart");
+ if (mPackageManager.isStorageLow()) {
+ return false;
+ }
+ final HashSet<String> pkgs = mPackageManager.getPackagesThatNeedDexOpt();
+ if (pkgs == null) {
+ return false;
+ }
+ mIdleTime.set(true);
+ new Thread("BackgroundDexOptService_DexOpter") {
+ @Override
+ public void run() {
+ for (String pkg : pkgs) {
+ if (!mIdleTime.get()) {
+ break;
+ }
+ mPackageManager.performDexOpt(pkg, false);
+ }
+ }
+ }.start();
+ return true;
+ }
+
+ public void onIdleStop() {
+ Log.i(TAG, "onIdleStop");
+ mIdleTime.set(false);
+ }
+}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 48e9737..bd28e04 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -239,8 +239,10 @@
private class MyPackageMonitor extends PackageMonitor {
- /** Checks if user is a profile of or same as listeningUser. */
- private boolean isProfileOf(UserHandle user, UserHandle listeningUser, String debugMsg) {
+ /** Checks if user is a profile of or same as listeningUser.
+ * and the user is enabled. */
+ private boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser,
+ String debugMsg) {
if (user.getIdentifier() == listeningUser.getIdentifier()) {
if (DEBUG) Log.d(TAG, "Delivering msg to same user " + debugMsg);
return true;
@@ -251,7 +253,8 @@
UserInfo listeningUserInfo = mUm.getUserInfo(listeningUser.getIdentifier());
if (userInfo == null || listeningUserInfo == null
|| userInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID
- || userInfo.profileGroupId != listeningUserInfo.profileGroupId) {
+ || userInfo.profileGroupId != listeningUserInfo.profileGroupId
+ || !userInfo.isEnabled()) {
if (DEBUG) {
Log.d(TAG, "Not delivering msg from " + user + " to " + listeningUser + ":"
+ debugMsg);
@@ -276,7 +279,7 @@
for (int i = 0; i < n; i++) {
IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
- if (!isProfileOf(user, listeningUser, "onPackageAdded")) continue;
+ if (!isEnabledProfileOf(user, listeningUser, "onPackageAdded")) continue;
try {
listener.onPackageAdded(user, packageName);
} catch (RemoteException re) {
@@ -295,7 +298,7 @@
for (int i = 0; i < n; i++) {
IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
- if (!isProfileOf(user, listeningUser, "onPackageRemoved")) continue;
+ if (!isEnabledProfileOf(user, listeningUser, "onPackageRemoved")) continue;
try {
listener.onPackageRemoved(user, packageName);
} catch (RemoteException re) {
@@ -314,7 +317,7 @@
for (int i = 0; i < n; i++) {
IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
- if (!isProfileOf(user, listeningUser, "onPackageModified")) continue;
+ if (!isEnabledProfileOf(user, listeningUser, "onPackageModified")) continue;
try {
listener.onPackageChanged(user, packageName);
} catch (RemoteException re) {
@@ -333,7 +336,7 @@
for (int i = 0; i < n; i++) {
IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
- if (!isProfileOf(user, listeningUser, "onPackagesAvailable")) continue;
+ if (!isEnabledProfileOf(user, listeningUser, "onPackagesAvailable")) continue;
try {
listener.onPackagesAvailable(user, packages, isReplacing());
} catch (RemoteException re) {
@@ -352,7 +355,7 @@
for (int i = 0; i < n; i++) {
IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
- if (!isProfileOf(user, listeningUser, "onPackagesUnavailable")) continue;
+ if (!isEnabledProfileOf(user, listeningUser, "onPackagesUnavailable")) continue;
try {
listener.onPackagesUnavailable(user, packages, isReplacing());
} catch (RemoteException re) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6a843a8..c8b61f1 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -23,17 +23,19 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.system.OsConstants.S_IRWXU;
+import static android.os.Process.PACKAGE_INFO_GID;
+import static android.os.Process.SYSTEM_UID;
import static android.system.OsConstants.S_IRGRP;
-import static android.system.OsConstants.S_IXGRP;
import static android.system.OsConstants.S_IROTH;
+import static android.system.OsConstants.S_IRWXU;
+import static android.system.OsConstants.S_IXGRP;
import static android.system.OsConstants.S_IXOTH;
-import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_USER_OWNER;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
+import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_USER_OWNER;
import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.internal.util.ArrayUtils.removeInt;
-import android.content.pm.PackageParser.*;
+import com.android.internal.R;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.app.ResolverActivity;
import com.android.internal.content.NativeLibraryHelper;
@@ -43,10 +45,13 @@
import com.android.internal.util.XmlUtils;
import com.android.server.EventLogTags;
import com.android.server.IntentResolver;
-import com.android.server.ServiceThread;
-
import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
import com.android.server.Watchdog;
+import com.android.server.pm.Settings.DatabaseVersion;
+import com.android.server.storage.DeviceStorageMonitorInternal;
+import com.android.server.storage.DeviceStorageMonitorInternal;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -82,6 +87,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageManager;
+import android.content.pm.PackageParser.ActivityIntentInfo;
import android.content.pm.PackageParser;
import android.content.pm.PackageStats;
import android.content.pm.PackageUserState;
@@ -125,6 +131,7 @@
import android.system.Os;
import android.system.StructStat;
import android.text.TextUtils;
+import android.util.AtomicFile;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -135,6 +142,7 @@
import android.util.Xml;
import android.view.Display;
+import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileDescriptor;
@@ -144,7 +152,9 @@
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
+import java.io.InputStream;
import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.Certificate;
@@ -163,14 +173,14 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import dalvik.system.DexFile;
+import dalvik.system.StaleDexCacheError;
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
-import com.android.internal.R;
-import com.android.server.pm.Settings.DatabaseVersion;
-import com.android.server.storage.DeviceStorageMonitorInternal;
-
/**
* Keep track of all those .apks everywhere.
*
@@ -197,6 +207,7 @@
private static final boolean DEBUG_PACKAGE_SCANNING = false;
private static final boolean DEBUG_APP_DIR_OBSERVER = false;
private static final boolean DEBUG_VERIFY = false;
+ private static final boolean DEBUG_DEXOPT = false;
private static final int RADIO_UID = Process.PHONE_UID;
private static final int LOG_UID = Process.LOG_UID;
@@ -287,7 +298,6 @@
final Context mContext;
final boolean mFactoryTest;
final boolean mOnlyCore;
- final boolean mNoDexOpt;
final DisplayMetrics mMetrics;
final int mDefParseFlags;
final String[] mSeparateProcesses;
@@ -593,6 +603,139 @@
private final String mRequiredVerifierPackage;
+ private final PackageUsage mPackageUsage = new PackageUsage();
+
+ private class PackageUsage {
+ private static final int WRITE_INTERVAL
+ = (DEBUG_DEXOPT) ? 0 : 30*60*1000; // 30m in ms
+
+ private final Object mFileLock = new Object();
+ private final AtomicLong mLastWritten = new AtomicLong(0);
+ private final AtomicBoolean mBackgroundWriteRunning = new AtomicBoolean(false);
+
+ void write(boolean force) {
+ if (force) {
+ write();
+ return;
+ }
+ if (SystemClock.elapsedRealtime() - mLastWritten.get() < WRITE_INTERVAL
+ && !DEBUG_DEXOPT) {
+ return;
+ }
+ if (mBackgroundWriteRunning.compareAndSet(false, true)) {
+ new Thread("PackageUsage_DiskWriter") {
+ @Override
+ public void run() {
+ try {
+ write(true);
+ } finally {
+ mBackgroundWriteRunning.set(false);
+ }
+ }
+ }.start();
+ }
+ }
+
+ private void write() {
+ synchronized (mPackages) {
+ synchronized (mFileLock) {
+ AtomicFile file = getFile();
+ FileOutputStream f = null;
+ try {
+ f = file.startWrite();
+ BufferedOutputStream out = new BufferedOutputStream(f);
+ FileUtils.setPermissions(file.getBaseFile().getPath(), 0660, SYSTEM_UID, PACKAGE_INFO_GID);
+ StringBuilder sb = new StringBuilder();
+ for (PackageParser.Package pkg : mPackages.values()) {
+ if (pkg.mLastPackageUsageTimeInMills == 0) {
+ continue;
+ }
+ sb.setLength(0);
+ sb.append(pkg.packageName);
+ sb.append(' ');
+ sb.append((long)pkg.mLastPackageUsageTimeInMills);
+ sb.append('\n');
+ out.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
+ }
+ out.flush();
+ file.finishWrite(f);
+ } catch (IOException e) {
+ if (f != null) {
+ file.failWrite(f);
+ }
+ Log.e(TAG, "Failed to write package usage times", e);
+ }
+ }
+ }
+ mLastWritten.set(SystemClock.elapsedRealtime());
+ }
+
+ void readLP() {
+ synchronized (mFileLock) {
+ AtomicFile file = getFile();
+ BufferedInputStream in = null;
+ try {
+ in = new BufferedInputStream(file.openRead());
+ StringBuffer sb = new StringBuffer();
+ while (true) {
+ String packageName = readToken(in, sb, ' ');
+ if (packageName == null) {
+ break;
+ }
+ String timeInMillisString = readToken(in, sb, '\n');
+ if (timeInMillisString == null) {
+ throw new IOException("Failed to find last usage time for package "
+ + packageName);
+ }
+ PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ continue;
+ }
+ long timeInMillis;
+ try {
+ timeInMillis = Long.parseLong(timeInMillisString.toString());
+ } catch (NumberFormatException e) {
+ throw new IOException("Failed to parse " + timeInMillisString
+ + " as a long.", e);
+ }
+ pkg.mLastPackageUsageTimeInMills = timeInMillis;
+ }
+ } catch (FileNotFoundException expected) {
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to read package usage times", e);
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
+ }
+ mLastWritten.set(SystemClock.elapsedRealtime());
+ }
+
+ private String readToken(InputStream in, StringBuffer sb, char endOfToken)
+ throws IOException {
+ sb.setLength(0);
+ while (true) {
+ int ch = in.read();
+ if (ch == -1) {
+ if (sb.length() == 0) {
+ return null;
+ }
+ throw new IOException("Unexpected EOF");
+ }
+ if (ch == endOfToken) {
+ return sb.toString();
+ }
+ sb.append((char)ch);
+ }
+ }
+
+ private AtomicFile getFile() {
+ File dataDir = Environment.getDataDirectory();
+ File systemDir = new File(dataDir, "system");
+ File fname = new File(systemDir, "package-usage.list");
+ return new AtomicFile(fname);
+ }
+ }
+
class PackageHandler extends Handler {
private boolean mBound = false;
final ArrayList<HandlerParams> mPendingInstalls =
@@ -1137,7 +1280,6 @@
mContext = context;
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
- mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
mMetrics = new DisplayMetrics();
mSettings = new Settings(context);
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
@@ -1223,10 +1365,6 @@
// Set flag to monitor and not change apk file paths when
// scanning install directories.
int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;
- if (mNoDexOpt) {
- Slog.w(TAG, "Running ENG build: no pre-dexopt!");
- scanMode |= SCAN_NO_DEX;
- }
final HashSet<String> alreadyDexOpted = new HashSet<String>();
@@ -1245,7 +1383,7 @@
Slog.w(TAG, "No BOOTCLASSPATH found!");
}
- boolean didDexOpt = false;
+ boolean didDexOptLibraryOrTool = false;
final List<String> instructionSets = getAllInstructionSets();
@@ -1265,13 +1403,12 @@
}
try {
- if (dalvik.system.DexFile.isDexOptNeededInternal(
- lib, null, instructionSet, false)) {
+ if (DexFile.isDexOptNeededInternal(lib, null, instructionSet, false)) {
alreadyDexOpted.add(lib);
// The list of "shared libraries" we have at this point is
mInstaller.dexopt(lib, Process.SYSTEM_UID, true, instructionSet);
- didDexOpt = true;
+ didDexOptLibraryOrTool = true;
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Library not found: " + lib);
@@ -1317,9 +1454,9 @@
continue;
}
try {
- if (dalvik.system.DexFile.isDexOptNeededInternal(path, null, instructionSet, false)) {
+ if (DexFile.isDexOptNeededInternal(path, null, instructionSet, false)) {
mInstaller.dexopt(path, Process.SYSTEM_UID, true, instructionSet);
- didDexOpt = true;
+ didDexOptLibraryOrTool = true;
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Jar not found: " + path);
@@ -1330,7 +1467,7 @@
}
}
- if (didDexOpt) {
+ if (didDexOptLibraryOrTool) {
pruneDexFiles(new File(dataDir, "dalvik-cache"));
}
@@ -1509,12 +1646,15 @@
// the correct library paths.
updateAllSharedLibrariesLPw();
-
for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
adjustCpuAbisForSharedUserLPw(setting.packages, true /* do dexopt */,
false /* force dexopt */, false /* defer dexopt */);
}
+ // Now that we know all the packages we are keeping,
+ // read and update their last usage times.
+ mPackageUsage.readLP();
+
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
Slog.i(TAG, "Time to scan packages: "
@@ -1573,6 +1713,14 @@
//
// Additionally, delete all dex files from the root directory
// since there shouldn't be any there anyway.
+ //
+ // Note: This isn't as good an indicator as it used to be. It
+ // used to include the boot classpath but at some point
+ // DexFile.isDexOptNeeded started returning false for the boot
+ // class path files in all cases. It is very possible in a
+ // small maintenance release update that the library and tool
+ // jars may be unchanged but APK could be removed resulting in
+ // unused dalvik-cache files.
File[] files = cacheDir.listFiles();
if (files != null) {
for (File file : files) {
@@ -1595,10 +1743,12 @@
}
}
+ @Override
public boolean isFirstBoot() {
return !mRestoredSettings;
}
+ @Override
public boolean isOnlyCoreApps() {
return mOnlyCore;
}
@@ -1895,6 +2045,7 @@
state, userId);
}
+ @Override
public boolean isPackageAvailable(String packageName, int userId) {
if (!sUserManager.exists(userId)) return false;
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "is package available");
@@ -1932,6 +2083,7 @@
return null;
}
+ @Override
public String[] currentToCanonicalPackageNames(String[] names) {
String[] out = new String[names.length];
// reader
@@ -1944,6 +2096,7 @@
return out;
}
+ @Override
public String[] canonicalToCurrentPackageNames(String[] names) {
String[] out = new String[names.length];
// reader
@@ -2004,6 +2157,7 @@
return pi;
}
+ @Override
public PermissionInfo getPermissionInfo(String name, int flags) {
// reader
synchronized (mPackages) {
@@ -2015,6 +2169,7 @@
}
}
+ @Override
public List<PermissionInfo> queryPermissionsByGroup(String group, int flags) {
// reader
synchronized (mPackages) {
@@ -2038,6 +2193,7 @@
}
}
+ @Override
public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) {
// reader
synchronized (mPackages) {
@@ -2046,6 +2202,7 @@
}
}
+ @Override
public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
// reader
synchronized (mPackages) {
@@ -2131,6 +2288,7 @@
}
+ @Override
public void freeStorageAndNotify(final long freeStorageSize, final IPackageDataObserver observer) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CLEAR_APP_CACHE, null);
@@ -2156,6 +2314,7 @@
});
}
+ @Override
public void freeStorage(final long freeStorageSize, final IntentSender pi) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CLEAR_APP_CACHE, null);
@@ -2277,6 +2436,7 @@
return null;
}
+ @Override
public String[] getSystemSharedLibraryNames() {
Set<String> libSet;
synchronized (mPackages) {
@@ -2291,6 +2451,7 @@
return null;
}
+ @Override
public FeatureInfo[] getSystemAvailableFeatures() {
Collection<FeatureInfo> featSet;
synchronized (mPackages) {
@@ -2309,6 +2470,7 @@
return null;
}
+ @Override
public boolean hasSystemFeature(String name) {
synchronized (mPackages) {
return mAvailableFeatures.containsKey(name);
@@ -2323,6 +2485,7 @@
+ " is not privileged to communicate with user=" + userId);
}
+ @Override
public int checkPermission(String permName, String pkgName) {
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(pkgName);
@@ -2340,6 +2503,7 @@
return PackageManager.PERMISSION_DENIED;
}
+ @Override
public int checkUidPermission(String permName, int uid) {
synchronized (mPackages) {
Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
@@ -2514,18 +2678,21 @@
return added;
}
+ @Override
public boolean addPermission(PermissionInfo info) {
synchronized (mPackages) {
return addPermissionLocked(info, false);
}
}
+ @Override
public boolean addPermissionAsync(PermissionInfo info) {
synchronized (mPackages) {
return addPermissionLocked(info, true);
}
}
+ @Override
public void removePermission(String name) {
synchronized (mPackages) {
checkPermissionTreeLP(name);
@@ -2570,6 +2737,7 @@
}
}
+ @Override
public void grantPermission(String packageName, String permissionName) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.GRANT_REVOKE_PERMISSIONS, null);
@@ -2599,6 +2767,7 @@
}
}
+ @Override
public void revokePermission(String packageName, String permissionName) {
int changedAppId = -1;
@@ -2657,12 +2826,14 @@
}
}
+ @Override
public boolean isProtectedBroadcast(String actionName) {
synchronized (mPackages) {
return mProtectedBroadcasts.contains(actionName);
}
}
+ @Override
public int checkSignatures(String pkg1, String pkg2) {
synchronized (mPackages) {
final PackageParser.Package p1 = mPackages.get(pkg1);
@@ -2675,6 +2846,7 @@
}
}
+ @Override
public int checkUidSignatures(int uid1, int uid2) {
// Map to base uids.
uid1 = UserHandle.getAppId(uid1);
@@ -2814,6 +2986,7 @@
return PackageManager.SIGNATURE_NO_MATCH;
}
+ @Override
public String[] getPackagesForUid(int uid) {
uid = UserHandle.getAppId(uid);
// reader
@@ -2837,6 +3010,7 @@
return null;
}
+ @Override
public String getNameForUid(int uid) {
// reader
synchronized (mPackages) {
@@ -2852,6 +3026,7 @@
return null;
}
+ @Override
public int getUidForSharedUser(String sharedUserName) {
if(sharedUserName == null) {
return -1;
@@ -2866,6 +3041,7 @@
}
}
+ @Override
public int getFlagsForUid(int uid) {
synchronized (mPackages) {
Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
@@ -3797,6 +3973,7 @@
}
}
+ @Override
public List<ProviderInfo> queryContentProviders(String processName,
int uid, int flags) {
ArrayList<ProviderInfo> finalList = null;
@@ -3834,6 +4011,7 @@
return finalList;
}
+ @Override
public InstrumentationInfo getInstrumentationInfo(ComponentName name,
int flags) {
// reader
@@ -3843,6 +4021,7 @@
}
}
+ @Override
public List<InstrumentationInfo> queryInstrumentation(String targetPackage,
int flags) {
ArrayList<InstrumentationInfo> finalList =
@@ -4289,21 +4468,60 @@
}
if (pkgs != null) {
+ // Filter out packages that aren't recently used.
+ //
+ // The exception is first boot of a non-eng device, which
+ // should do a full dexopt.
+ boolean eng = "eng".equals(SystemProperties.get("ro.build.type"));
+ if (eng || !isFirstBoot()) {
+ // TODO: add a property to control this?
+ long dexOptLRUThresholdInMinutes;
+ if (eng) {
+ dexOptLRUThresholdInMinutes = 30; // only last 30 minutes of apps for eng builds.
+ } else {
+ dexOptLRUThresholdInMinutes = 7 * 24 * 60; // apps used in the 7 days for users.
+ }
+ long dexOptLRUThresholdInMills = dexOptLRUThresholdInMinutes * 60 * 1000;
+
+ int total = pkgs.size();
+ int skipped = 0;
+ long now = System.currentTimeMillis();
+ for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) {
+ PackageParser.Package pkg = i.next();
+ long then = pkg.mLastPackageUsageTimeInMills;
+ if (then + dexOptLRUThresholdInMills < now) {
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Skipping dexopt of " + pkg.packageName + " last resumed: " +
+ ((then == 0) ? "never" : new Date(then)));
+ }
+ i.remove();
+ skipped++;
+ }
+ }
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Skipped optimizing " + skipped + " of " + total);
+ }
+ }
+
int i = 0;
for (PackageParser.Package pkg : pkgs) {
+ i++;
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Optimizing app " + i + " of " + pkgs.size()
+ + ": " + pkg.packageName);
+ }
if (!isFirstBoot()) {
- i++;
try {
ActivityManagerNative.getDefault().showBootMessage(
mContext.getResources().getString(
- com.android.internal.R.string.android_upgrading_apk,
+ R.string.android_upgrading_apk,
i, pkgs.size()), true);
} catch (RemoteException e) {
}
}
PackageParser.Package p = pkg;
synchronized (mInstallLock) {
- if (!p.mDidDexOpt) {
+ if (p.mDexOptNeeded) {
performDexOptLI(p, false /* force dex */, false /* defer */,
true /* include dependencies */);
}
@@ -4315,25 +4533,57 @@
@Override
public boolean performDexOpt(String packageName) {
enforceSystemOrRoot("Only the system can request dexopt be performed");
- if (!mNoDexOpt) {
- return false;
- }
+ return performDexOpt(packageName, true);
+ }
+
+ public boolean performDexOpt(String packageName, boolean updateUsage) {
PackageParser.Package p;
synchronized (mPackages) {
p = mPackages.get(packageName);
- if (p == null || p.mDidDexOpt) {
+ if (p == null) {
+ return false;
+ }
+ if (updateUsage) {
+ p.mLastPackageUsageTimeInMills = System.currentTimeMillis();
+ }
+ mPackageUsage.write();
+ if (!p.mDexOptNeeded) {
return false;
}
}
+
synchronized (mInstallLock) {
return performDexOptLI(p, false /* force dex */, false /* defer */,
true /* include dependencies */) == DEX_OPT_PERFORMED;
}
}
- private void performDexOptLibsLI(ArrayList<String> libs, String instructionSet, boolean forceDex,
- boolean defer, HashSet<String> done) {
+ public HashSet<String> getPackagesThatNeedDexOpt() {
+ HashSet<String> pkgs = null;
+ synchronized (mPackages) {
+ for (PackageParser.Package p : mPackages.values()) {
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, p.packageName + " mDexOptNeeded=" + p.mDexOptNeeded);
+ }
+ if (!p.mDexOptNeeded) {
+ continue;
+ }
+ if (pkgs == null) {
+ pkgs = new HashSet<String>();
+ }
+ pkgs.add(p.packageName);
+ }
+ }
+ return pkgs;
+ }
+
+ public void shutdown() {
+ mPackageUsage.write(true);
+ }
+
+ private void performDexOptLibsLI(ArrayList<String> libs, String instructionSet,
+ boolean forceDex, boolean defer, HashSet<String> done) {
for (int i=0; i<libs.size(); i++) {
PackageParser.Package libPkg;
String libName;
@@ -4358,8 +4608,7 @@
static final int DEX_OPT_FAILED = -1;
private int performDexOptLI(PackageParser.Package pkg, String instructionSetOverride,
- boolean forceDex,
- boolean defer, HashSet<String> done) {
+ boolean forceDex, boolean defer, HashSet<String> done) {
final String instructionSet = instructionSetOverride != null ?
instructionSetOverride : getAppInstructionSet(pkg.applicationInfo);
@@ -4376,47 +4625,52 @@
boolean performed = false;
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
String path = pkg.mScanPath;
- int ret = 0;
try {
- if (forceDex || dalvik.system.DexFile.isDexOptNeededInternal(path,
- pkg.packageName, instructionSet, defer)) {
- if (!forceDex && defer) {
- if (mDeferredDexOpt == null) {
- mDeferredDexOpt = new HashSet<PackageParser.Package>();
- }
- mDeferredDexOpt.add(pkg);
- return DEX_OPT_DEFERRED;
- } else {
- Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName +
- " (instructionSet=" + instructionSet + ")");
-
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
+ boolean isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path,
+ pkg.packageName,
+ instructionSet,
+ defer);
+ // There are three basic cases here:
+ // 1.) we need to dexopt, either because we are forced or it is needed
+ // 2.) we are defering a needed dexopt
+ // 3.) we are skipping an unneeded dexopt
+ if (forceDex || (!defer && isDexOptNeededInternal)) {
+ Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName);
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
pkg.packageName, instructionSet);
- pkg.mDidDexOpt = true;
- performed = true;
+ // Note that we ran dexopt, since rerunning will
+ // probably just result in an error again.
+ pkg.mDexOptNeeded = false;
+ if (ret < 0) {
+ return DEX_OPT_FAILED;
}
+ return DEX_OPT_PERFORMED;
}
+ if (defer && isDexOptNeededInternal) {
+ if (mDeferredDexOpt == null) {
+ mDeferredDexOpt = new HashSet<PackageParser.Package>();
+ }
+ mDeferredDexOpt.add(pkg);
+ return DEX_OPT_DEFERRED;
+ }
+ pkg.mDexOptNeeded = false;
+ return DEX_OPT_SKIPPED;
} catch (FileNotFoundException e) {
Slog.w(TAG, "Apk not found for dexopt: " + path);
- ret = -1;
+ return DEX_OPT_FAILED;
} catch (IOException e) {
Slog.w(TAG, "IOException reading apk: " + path, e);
- ret = -1;
- } catch (dalvik.system.StaleDexCacheError e) {
+ return DEX_OPT_FAILED;
+ } catch (StaleDexCacheError e) {
Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
- ret = -1;
+ return DEX_OPT_FAILED;
} catch (Exception e) {
Slog.w(TAG, "Exception when doing dexopt : ", e);
- ret = -1;
- }
- if (ret < 0) {
- //error from installer
return DEX_OPT_FAILED;
}
}
-
- return performed ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
+ return DEX_OPT_SKIPPED;
}
private String getAppInstructionSet(ApplicationInfo info) {
@@ -4705,7 +4959,7 @@
mResolveActivity.processName = "system:ui";
mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
- mResolveActivity.theme = com.android.internal.R.style.Theme_Holo_Dialog_Alert;
+ mResolveActivity.theme = R.style.Theme_Holo_Dialog_Alert;
mResolveActivity.exported = true;
mResolveActivity.enabled = true;
mResolveInfo.activityInfo = mResolveActivity;
@@ -7064,6 +7318,7 @@
return mMediaMounted || Environment.isExternalStorageEmulated();
}
+ @Override
public PackageCleanItem nextPackageToClean(PackageCleanItem lastPackage) {
// writer
synchronized (mPackages) {
@@ -7249,6 +7504,7 @@
}
/* Called when a downloaded package installation has been confirmed by the user */
+ @Override
public void installPackage(
final Uri packageURI, final IPackageInstallObserver observer, final int flags,
final String installerPackageName) {
@@ -7266,6 +7522,7 @@
installerPackageName, verificationParams, encryptionParams);
}
+ @Override
public void installPackageWithVerificationAndEncryption(Uri packageURI,
IPackageInstallObserver observer, int flags, String installerPackageName,
VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
@@ -7479,11 +7736,7 @@
null);
PackageSetting pkgSetting;
final int uid = Binder.getCallingUid();
- if (UserHandle.getUserId(uid) != userId) {
- mContext.enforceCallingPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- "installExistingPackage for user " + userId);
- }
+ enforceCrossUserPermission(uid, userId, true, "installExistingPackage for user " + userId);
if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
return PackageManager.INSTALL_FAILED_USER_RESTRICTED;
}
@@ -7679,6 +7932,7 @@
}
}
+ @Override
public void finishPackageInstall(int token) {
enforceSystemOrRoot("Only the system is allowed to finish installs");
@@ -7750,6 +8004,7 @@
-1);
}
+ @Override
public void setInstallerPackageName(String targetPackage, String installerPackageName) {
final int uid = Binder.getCallingUid();
// writer
@@ -9705,22 +9960,22 @@
// Utility method used to move dex files during install.
private int moveDexFilesLI(PackageParser.Package newPackage) {
- int retCode;
if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
- retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath,
- getAppInstructionSet(newPackage.applicationInfo));
+ final String instructionSet = getAppInstructionSet(newPackage.applicationInfo);
+ int retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath,
+ instructionSet);
if (retCode != 0) {
- if (mNoDexOpt) {
- /*
- * If we're in an engineering build, programs are lazily run
- * through dexopt. If the .dex file doesn't exist yet, it
- * will be created when the program is run next.
- */
- Slog.i(TAG, "dex file doesn't exist, skipping move: " + newPackage.mPath);
- } else {
- Slog.e(TAG, "Couldn't rename dex file: " + newPackage.mPath);
- return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- }
+ /*
+ * Programs may be lazily run through dexopt, so the
+ * source may not exist. However, something seems to
+ * have gone wrong, so note that dexopt needs to be
+ * run again and remove the source file. In addition,
+ * remove the target to make sure there isn't a stale
+ * file from a previous version of the package.
+ */
+ newPackage.mDexOptNeeded = true;
+ mInstaller.rmdex(newPackage.mScanPath, instructionSet);
+ mInstaller.rmdex(newPackage.mPath, instructionSet);
}
}
return PackageManager.INSTALL_SUCCEEDED;
@@ -10684,6 +10939,7 @@
}
}
+ @Override
public void deleteApplicationCacheFiles(final String packageName,
final IPackageDataObserver observer) {
mContext.enforceCallingOrSelfPermission(
@@ -10736,6 +10992,7 @@
return true;
}
+ @Override
public void getPackageSizeInfo(final String packageName, int userHandle,
final IPackageStatsObserver observer) {
mContext.enforceCallingOrSelfPermission(
@@ -10815,14 +11072,17 @@
}
+ @Override
public void addPackageToPreferred(String packageName) {
Slog.w(TAG, "addPackageToPreferred: this is now a no-op");
}
+ @Override
public void removePackageFromPreferred(String packageName) {
Slog.w(TAG, "removePackageFromPreferred: this is now a no-op");
}
+ @Override
public List<PackageInfo> getPreferredPackages(int flags) {
return new ArrayList<PackageInfo>();
}
@@ -10850,6 +11110,7 @@
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
+ @Override
public void addPreferredActivity(IntentFilter filter, int match,
ComponentName[] set, ComponentName activity, int userId) {
addPreferredActivityInternal(filter, match, set, activity, true, userId);
@@ -10886,6 +11147,7 @@
}
}
+ @Override
public void replacePreferredActivity(IntentFilter filter, int match,
ComponentName[] set, ComponentName activity) {
if (filter.countActions() != 1) {
@@ -10942,6 +11204,7 @@
}
}
+ @Override
public void clearPackagePreferredActivities(String packageName) {
final int uid = Binder.getCallingUid();
// writer
@@ -11005,6 +11268,7 @@
return changed;
}
+ @Override
public void resetPreferredActivities(int userId) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
@@ -11018,6 +11282,7 @@
}
}
+ @Override
public int getPreferredActivities(List<IntentFilter> outFilters,
List<ComponentName> outActivities, String packageName) {
@@ -11325,6 +11590,7 @@
new int[] {UserHandle.getUserId(packageUid)});
}
+ @Override
public void setPackageStoppedState(String packageName, boolean stopped, int userId) {
if (!sUserManager.exists(userId)) return;
final int uid = Binder.getCallingUid();
@@ -11341,6 +11607,7 @@
}
}
+ @Override
public String getInstallerPackageName(String packageName) {
// reader
synchronized (mPackages) {
@@ -11370,6 +11637,7 @@
}
}
+ @Override
public void enterSafeMode() {
enforceSystemOrRoot("Only the system can request entering safe mode");
@@ -11378,6 +11646,7 @@
}
}
+ @Override
public void systemReady() {
mSystemReady = true;
@@ -11423,10 +11692,12 @@
sUserManager.systemReady();
}
+ @Override
public boolean isSafeMode() {
return mSafeMode;
}
+ @Override
public boolean hasSystemUidErrors() {
return mHasSystemUidErrors;
}
@@ -11924,6 +12195,7 @@
/*
* Update media status on PackageManager.
*/
+ @Override
public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) {
int callingUid = Binder.getCallingUid();
if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
@@ -12518,6 +12790,7 @@
});
}
+ @Override
public boolean setInstallLocation(int loc) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
null);
@@ -12533,6 +12806,7 @@
return false;
}
+ @Override
public int getInstallLocation() {
return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
android.provider.Settings.Global.DEFAULT_INSTALL_LOCATION,
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 3239b46..60c6313 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -734,6 +734,18 @@
writeBoolean(serializer, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER);
writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS);
writeBoolean(serializer, restrictions, UserManager.DISALLOW_REMOVE_USER);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_DEBUGGING_FEATURES);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_VPN);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_TETHERING);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_FACTORY_RESET);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_ADD_USER);
+ writeBoolean(serializer, restrictions, UserManager.ENSURE_VERIFY_APPS);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_CELL_BROADCASTS);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_APPS);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_UNMUTE_MICROPHONE);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_ADJUST_VOLUME);
serializer.endTag(null, TAG_RESTRICTIONS);
}
serializer.endTag(null, TAG_USER);
@@ -873,6 +885,19 @@
readBoolean(parser, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER);
readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS);
readBoolean(parser, restrictions, UserManager.DISALLOW_REMOVE_USER);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_DEBUGGING_FEATURES);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_VPN);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_TETHERING);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_FACTORY_RESET);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_ADD_USER);
+ readBoolean(parser, restrictions, UserManager.ENSURE_VERIFY_APPS);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_CELL_BROADCASTS);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_APPS);
+ readBoolean(parser, restrictions,
+ UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_UNMUTE_MICROPHONE);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_ADJUST_VOLUME);
}
}
}
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 8fed79f..956e3e6 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -45,6 +45,7 @@
import android.os.storage.IMountShutdownObserver;
import com.android.internal.telephony.ITelephony;
+import com.android.server.pm.PackageManagerService;
import android.util.Log;
import android.view.WindowManager;
@@ -329,6 +330,14 @@
}
}
+ Log.i(TAG, "Shutting down package manager...");
+
+ final PackageManagerService pm = (PackageManagerService)
+ ServiceManager.getService("package");
+ if (pm != null) {
+ pm.shutdown();
+ }
+
// Shutdown radios.
shutdownRadios(MAX_RADIO_WAIT_TIME);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 022bdae..738ad32 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -74,6 +74,7 @@
private boolean mMenuVisible = false;
private int mImeWindowVis = 0;
private int mImeBackDisposition;
+ private boolean mShowImeSwitcher;
private IBinder mImeToken = null;
private int mCurrentUserId;
@@ -346,7 +347,8 @@
}
@Override
- public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition) {
+ public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition,
+ final boolean showImeSwitcher) {
enforceStatusBar();
if (SPEW) {
@@ -360,11 +362,12 @@
mImeWindowVis = vis;
mImeBackDisposition = backDisposition;
mImeToken = token;
+ mShowImeSwitcher = showImeSwitcher;
mHandler.post(new Runnable() {
public void run() {
if (mBar != null) {
try {
- mBar.setImeWindowStatus(token, vis, backDisposition);
+ mBar.setImeWindowStatus(token, vis, backDisposition, showImeSwitcher);
} catch (RemoteException ex) {
}
}
@@ -512,6 +515,7 @@
switches[2] = mMenuVisible ? 1 : 0;
switches[3] = mImeWindowVis;
switches[4] = mImeBackDisposition;
+ switches[7] = mShowImeSwitcher ? 1 : 0;
binders.add(mImeToken);
}
switches[5] = mWindowManager.isHardKeyboardAvailable() ? 1 : 0;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4318b0e..e746c1a 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -299,6 +299,7 @@
boolean mHasSurface = false;
+ boolean mNotOnAppsDisplay = false;
DisplayContent mDisplayContent;
/** When true this window can be displayed on screens owther than mOwnerUid's */
@@ -430,6 +431,10 @@
}
mRootToken = appToken;
mAppToken = appToken.appWindowToken;
+ if (mAppToken != null) {
+ final DisplayContent appDisplay = getDisplayContent();
+ mNotOnAppsDisplay = displayContent != appDisplay;
+ }
mWinAnimator = new WindowStateAnimator(this);
mWinAnimator.mAlpha = a.alpha;
@@ -717,7 +722,8 @@
}
public DisplayContent getDisplayContent() {
- return mAppToken == null ? mDisplayContent : getStack().getDisplayContent();
+ return mAppToken == null || mNotOnAppsDisplay ?
+ mDisplayContent : getStack().getDisplayContent();
}
public int getDisplayId() {
diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp
index 163692b..163225e 100644
--- a/services/core/jni/com_android_server_AssetAtlasService.cpp
+++ b/services/core/jni/com_android_server_AssetAtlasService.cpp
@@ -46,33 +46,16 @@
// ----------------------------------------------------------------------------
static struct {
- jfieldID mFinalizer;
- jfieldID mNativeCanvas;
+ jmethodID safeCanvasSwap;
} gCanvasClassInfo;
-static struct {
- jfieldID mNativeCanvas;
-} gCanvasFinalizerClassInfo;
-
-#define GET_LONG(object, field) \
- env->GetLongField(object, field)
-
-#define SET_LONG(object, field, value) \
- env->SetLongField(object, field, value)
+#define INVOKEV(object, method, ...) \
+ env->CallVoidMethod(object, method, __VA_ARGS__)
// ----------------------------------------------------------------------------
// Canvas management
// ----------------------------------------------------------------------------
-static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
- jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
- SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
- GET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas));
- SET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas, (long) newCanvas);
- SET_LONG(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (long) newCanvas);
- SkSafeUnref(previousCanvas);
-}
-
static jlong com_android_server_AssetAtlasService_acquireCanvas(JNIEnv* env, jobject,
jobject canvas, jint width, jint height) {
@@ -82,7 +65,7 @@
bitmap->eraseColor(0);
SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (*bitmap));
- swapCanvasPtr(env, canvas, nativeCanvas);
+ INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
return reinterpret_cast<jlong>(bitmap);
}
@@ -92,7 +75,7 @@
SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
SkCanvas* nativeCanvas = SkNEW(SkCanvas);
- swapCanvasPtr(env, canvas, nativeCanvas);
+ INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
delete bitmap;
}
@@ -242,9 +225,9 @@
var = env->FindClass(className); \
LOG_FATAL_IF(! var, "Unable to find class " className);
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
- var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
- LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+ var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+ LOG_FATAL_IF(!var, "Unable to find method " methodName);
const char* const kClassPathName = "com/android/server/AssetAtlasService";
@@ -261,12 +244,7 @@
jclass clazz;
FIND_CLASS(clazz, "android/graphics/Canvas");
- GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer",
- "Landroid/graphics/Canvas$CanvasFinalizer;");
- GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
-
- FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer");
- GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
+ GET_METHOD_ID(gCanvasClassInfo.safeCanvasSwap, clazz, "safeCanvasSwap", "(JZ)V");
return jniRegisterNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7a0d1c7..9a9f1c8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -44,12 +44,13 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -99,6 +100,7 @@
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -231,6 +233,8 @@
static class ActiveAdmin {
private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
private static final String TAG_DISABLE_CAMERA = "disable-camera";
+ private static final String TAG_DISABLE_ACCOUNT_MANAGEMENT = "disable-account-management";
+ private static final String TAG_ACCOUNT_TYPE = "account-type";
private static final String TAG_ENCRYPTION_REQUESTED = "encryption-requested";
private static final String TAG_PASSWORD_EXPIRATION_DATE = "password-expiration-date";
private static final String TAG_PASSWORD_EXPIRATION_TIMEOUT = "password-expiration-timeout";
@@ -296,6 +300,7 @@
boolean encryptionRequested = false;
boolean disableCamera = false;
+ Set<String> accountTypesWithManagementDisabled = new HashSet<String>();
// TODO: review implementation decisions with frameworks team
boolean specifiesGlobalProxy = false;
@@ -412,6 +417,15 @@
out.attribute(null, ATTR_VALUE, Integer.toString(disabledKeyguardFeatures));
out.endTag(null, TAG_DISABLE_KEYGUARD_FEATURES);
}
+ if (!accountTypesWithManagementDisabled.isEmpty()) {
+ out.startTag(null, TAG_DISABLE_ACCOUNT_MANAGEMENT);
+ for (String ac : accountTypesWithManagementDisabled) {
+ out.startTag(null, TAG_ACCOUNT_TYPE);
+ out.attribute(null, ATTR_VALUE, ac);
+ out.endTag(null, TAG_ACCOUNT_TYPE);
+ }
+ out.endTag(null, TAG_DISABLE_ACCOUNT_MANAGEMENT);
+ }
}
void readFromXml(XmlPullParser parser)
@@ -483,6 +497,23 @@
} else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) {
disabledKeyguardFeatures = Integer.parseInt(
parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_DISABLE_ACCOUNT_MANAGEMENT.equals(tag)) {
+ int outerDepthDAM = parser.getDepth();
+ int typeDAM;
+ while ((typeDAM=parser.next()) != XmlPullParser.END_DOCUMENT
+ && (typeDAM != XmlPullParser.END_TAG
+ || parser.getDepth() > outerDepthDAM)) {
+ if (typeDAM == XmlPullParser.END_TAG || typeDAM == XmlPullParser.TEXT) {
+ continue;
+ }
+ String tagDAM = parser.getName();
+ if (TAG_ACCOUNT_TYPE.equals(tagDAM)) {
+ accountTypesWithManagementDisabled.add(
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else {
+ Slog.w(LOG_TAG, "Unknown tag under " + tag + ": " + tagDAM);
+ }
+ }
} else {
Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
}
@@ -2532,7 +2563,7 @@
exclusionList = exclusionList.trim();
ContentResolver res = mContext.getContentResolver();
- ProxyProperties proxyProperties = new ProxyProperties(data[0], proxyPort, exclusionList);
+ ProxyInfo proxyProperties = new ProxyInfo(data[0], proxyPort, exclusionList);
if (!proxyProperties.isValid()) {
Slog.e(LOG_TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
return;
@@ -3023,6 +3054,7 @@
}
}
+ @Override
public void addPersistentPreferredActivity(ComponentName who, IntentFilter filter,
ComponentName activity) {
synchronized (this) {
@@ -3043,6 +3075,7 @@
}
}
+ @Override
public void clearPackagePersistentPreferredActivities(ComponentName who, String packageName) {
synchronized (this) {
if (who == null) {
@@ -3168,4 +3201,147 @@
}
}
}
+
+ @Override
+ public void enableSystemApp(ComponentName who, String packageName) {
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+ int userId = UserHandle.getCallingUserId();
+ long id = Binder.clearCallingIdentity();
+
+ try {
+ UserManager um = UserManager.get(mContext);
+ if (!um.getUserInfo(userId).isManagedProfile()) {
+ throw new IllegalStateException(
+ "Only call this method from a managed profile.");
+ }
+
+ // TODO: Use UserManager::getProfileParent when available.
+ UserInfo primaryUser = um.getUserInfo(UserHandle.USER_OWNER);
+
+ if (DBG) {
+ Slog.v(LOG_TAG, "installing " + packageName + " for "
+ + userId);
+ }
+
+ IPackageManager pm = AppGlobals.getPackageManager();
+ if (!isSystemApp(pm, packageName, primaryUser.id)) {
+ throw new IllegalArgumentException("Only system apps can be enabled this way.");
+ }
+
+ // Install the app.
+ pm.installExistingPackageAsUser(packageName, userId);
+
+ } catch (RemoteException re) {
+ // shouldn't happen
+ Slog.wtf(LOG_TAG, "Failed to install " + packageName, re);
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ }
+ }
+
+ @Override
+ public int enableSystemAppWithIntent(ComponentName who, Intent intent) {
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+ int userId = UserHandle.getCallingUserId();
+ long id = Binder.clearCallingIdentity();
+
+ try {
+ UserManager um = UserManager.get(mContext);
+ if (!um.getUserInfo(userId).isManagedProfile()) {
+ throw new IllegalStateException(
+ "Only call this method from a managed profile.");
+ }
+
+ // TODO: Use UserManager::getProfileParent when available.
+ UserInfo primaryUser = um.getUserInfo(UserHandle.USER_OWNER);
+
+ IPackageManager pm = AppGlobals.getPackageManager();
+ List<ResolveInfo> activitiesToEnable = pm.queryIntentActivities(intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ 0, // no flags
+ primaryUser.id);
+
+ if (DBG) Slog.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable);
+ int numberOfAppsInstalled = 0;
+ if (activitiesToEnable != null) {
+ for (ResolveInfo info : activitiesToEnable) {
+ if (info.activityInfo != null) {
+
+ if (!isSystemApp(pm, info.activityInfo.packageName, primaryUser.id)) {
+ throw new IllegalArgumentException(
+ "Only system apps can be enabled this way.");
+ }
+
+
+ numberOfAppsInstalled++;
+ pm.installExistingPackageAsUser(info.activityInfo.packageName, userId);
+ }
+ }
+ }
+ return numberOfAppsInstalled;
+ } catch (RemoteException e) {
+ // shouldn't happen
+ Slog.wtf(LOG_TAG, "Failed to resolve intent for: " + intent);
+ return 0;
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ }
+ }
+
+ private boolean isSystemApp(IPackageManager pm, String packageName, int userId)
+ throws RemoteException {
+ ApplicationInfo appInfo = pm.getApplicationInfo(packageName, 0, userId);
+ return (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) > 0;
+ }
+
+ @Override
+ public void setAccountManagementDisabled(ComponentName who, String accountType,
+ boolean disabled) {
+ if (!mHasFeature) {
+ return;
+ }
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (disabled) {
+ ap.accountTypesWithManagementDisabled.add(accountType);
+ } else {
+ ap.accountTypesWithManagementDisabled.remove(accountType);
+ }
+ saveSettingsLocked(UserHandle.getCallingUserId());
+ }
+ }
+
+ @Override
+ public String[] getAccountTypesWithManagementDisabled() {
+ if (!mHasFeature) {
+ return null;
+ }
+ synchronized (this) {
+ DevicePolicyData policy = getUserData(UserHandle.getCallingUserId());
+ final int N = policy.mAdminList.size();
+ HashSet<String> resultSet = new HashSet<String>();
+ for (int i = 0; i < N; i++) {
+ ActiveAdmin admin = policy.mAdminList.get(i);
+ resultSet.addAll(admin.accountTypesWithManagementDisabled);
+ }
+ return resultSet.toArray(new String[resultSet.size()]);
+ }
+ }
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 7c9f7a8..716823c 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -73,6 +73,7 @@
import com.android.server.net.NetworkStatsService;
import com.android.server.notification.NotificationManagerService;
import com.android.server.os.SchedulingPolicyService;
+import com.android.server.pm.BackgroundDexOptService;
import com.android.server.pm.Installer;
import com.android.server.pm.LauncherAppsService;
import com.android.server.pm.PackageManagerService;
@@ -604,6 +605,14 @@
if (!disableNetwork) {
try {
+ Slog.i(TAG, "Network Score Service");
+ networkScore = new NetworkScoreService(context);
+ ServiceManager.addService(Context.NETWORK_SCORE_SERVICE, networkScore);
+ } catch (Throwable e) {
+ reportWtf("starting Network Score Service", e);
+ }
+
+ try {
Slog.i(TAG, "NetworkStats Service");
networkStats = new NetworkStatsService(context, networkManagement, alarm);
ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
@@ -641,6 +650,15 @@
}
try {
+ Slog.i(TAG, "Wi-Fi Scanning Service");
+ mSystemServiceManager.startService(
+ "com.android.server.wifi.WifiScanningService");
+
+ } catch (Throwable e) {
+ reportWtf("starting Wi-Fi Scanning Service", e);
+ }
+
+ try {
Slog.i(TAG, "Connectivity Service");
connectivity = new ConnectivityService(
context, networkManagement, networkStats, networkPolicy);
@@ -652,14 +670,6 @@
}
try {
- Slog.i(TAG, "Network Score Service");
- networkScore = new NetworkScoreService(context);
- ServiceManager.addService(Context.NETWORK_SCORE_SERVICE, networkScore);
- } catch (Throwable e) {
- reportWtf("starting Network Score Service", e);
- }
-
- try {
Slog.i(TAG, "Network Service Discovery Service");
serviceDiscovery = NsdService.create(context);
ServiceManager.addService(
@@ -962,6 +972,13 @@
} catch (Throwable e) {
Slog.e(TAG, "Failure starting TrustManagerService", e);
}
+
+ try {
+ Slog.i(TAG, "BackgroundDexOptService");
+ new BackgroundDexOptService(context);
+ } catch (Throwable e) {
+ reportWtf("starting BackgroundDexOptService", e);
+ }
}
try {
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index af0d0ad..3e9cf43 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -232,6 +232,15 @@
<category android:name="com.android.test.hwui.TEST" />
</intent-filter>
</activity>
+
+ <activity
+ android:name="LooperAcceleration"
+ android:label="Misc/LooperAcceleration">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.hwui.TEST" />
+ </intent-filter>
+ </activity>
<activity
android:name="TextFadeActivity"
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.java b/tests/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.java
new file mode 100644
index 0000000..20d8e11
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.graphics.Canvas;
+import android.os.Bundle;
+import android.os.Looper;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.webkit.WebChromeClient;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.LinearLayout;
+
+public class LooperAcceleration extends Activity {
+
+ static final boolean INCLUDE_WEBVIEW = false;
+
+ static class IsAcceleratedView extends View {
+
+ public IsAcceleratedView(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (canvas.isHardwareAccelerated()) {
+ canvas.drawARGB(0xFF, 0x00, 0xFF, 0x00);
+ } else {
+ canvas.drawARGB(0xFF, 0xFF, 0x00, 0x00);
+ }
+ }
+
+ }
+
+ private View makeView() {
+ LinearLayout layout = new LinearLayout(this);
+ layout.addView(new IsAcceleratedView(this), LayoutParams.MATCH_PARENT, 60);
+
+ if (INCLUDE_WEBVIEW) {
+ WebView wv = new WebView(this);
+ wv.setWebViewClient(new WebViewClient());
+ wv.setWebChromeClient(new WebChromeClient());
+ wv.loadUrl("http://www.webkit.org/blog-files/3d-transforms/poster-circle.html");
+ layout.addView(wv, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ }
+ return layout;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(makeView());
+
+ new Thread() {
+ @Override
+ public void run() {
+ Looper.prepare();
+ final Context context = LooperAcceleration.this;
+ Dialog dlg = new Dialog(context);
+ dlg.addContentView(makeView(), new LayoutParams(300, 400));
+ dlg.setCancelable(true);
+ dlg.setCanceledOnTouchOutside(true);
+ dlg.setOnDismissListener(new DialogInterface.OnDismissListener() {
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ Looper.myLooper().quit();
+ }
+ });
+ dlg.setTitle("Not Looper.getMainLooper() check");
+ dlg.show();
+ Looper.loop();
+ }
+ }.start();
+ }
+}
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
index 2e029f0..b7dcef7 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
@@ -84,11 +84,12 @@
Log.d(TAG, "Creating session for package " + mContext.getBasePackageName());
mSession = man.createSession("OneMedia");
mSession.addCallback(mCallback);
- mPerformer = mSession.setTransportPerformerEnabled();
+ mPerformer = mSession.getTransportPerformer();
mPerformer.addListener(new TransportListener());
mPerformer.setPlaybackState(mPlaybackState);
+ mSession.setFlags(Session.FLAG_HANDLES_TRANSPORT_CONTROLS);
mSession.setRouteOptions(mRouteOptions);
- mSession.publish();
+ mSession.setActive(true);
}
public void onDestroy() {
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
index bb2bebf..d0f2a2d 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:trigger="state_checked" android:versionCode="1" >
+ android:versionCode="1" >
<size
android:height="48dp"
@@ -26,53 +26,11 @@
<group>
<path
- android:name="check"
- android:pathData="m20,200l100,90l180,-180l-35,-35l-145,145l-60,-60l-40,40z"
- android:fill="?android:attr/colorControlActivated" />
- </group>
- <group>
- <path
android:name="box1"
- android:pathData="m127,171l37,38l33,-31l-37,-40l-1,3l-2,0l-30,30z"
+ android:pathData="m20,200l100,90l180,-180l-35,-35l-145,145l-60,-60l-40,40z"
android:fill="?android:attr/colorControlActivated"
android:stroke="?android:attr/colorControlActivated"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
- <group>
- <path
- android:name="box2"
- android:pathData="m127,171l37,38l33,-31l-37,-40l-1,3l-2,0l-30,30z"
- android:rotation="46.757"
- android:pivotX="162"
- android:pivotY="173.5"
- android:fill="?android:attr/colorControlNormal"
- android:stroke="?android:attr/colorControlNormal"
- android:strokeWidth="3"
- android:strokeLineCap="round"
- android:strokeLineJoin="round" />
- </group>
- <group>
- <path
- android:name="box3"
- android:pathData="m187,147l-1,55l-49,-1l2,-53l48,0z"
- android:stroke="?android:attr/colorControlNormal"
- android:strokeWidth="10"
- android:strokeLineCap="round"
- android:strokeLineJoin="round" />
- </group>
- <group>
- <path
- android:name="box4"
- android:pathData="m248,74l0,164l-177,0l1,-165l173,-1l3,2z"
- android:stroke="?android:attr/colorControlNormal"
- android:strokeWidth="30"
- android:strokeLineCap="round"
- android:strokeLineJoin="round" />
- </group>
-
- <animation
- android:durations="300,100,0,300"
- android:sequence="check,box1,box2,box3,box4" />
-
</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
index 49906d17..728624a 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
@@ -23,14 +23,6 @@
<group>
<path
- android:name="arrow"
- android:pathData="M 100,225 L 100,115 L 130,115 L 70,15 L 10,115 L 40,115 L 40,225 z"
- android:fill="#ffffffff"
- android:stroke="#FF00FF00"
- android:strokeWidth="1"/>
- </group>
- <group>
- <path
android:name="house"
android:pathData="M 130,225 L 130,115 L 130,115 L 70,15 L 10,115 L 10,115 L 10,225 z"
android:fill="#ff440000"
@@ -42,5 +34,4 @@
android:trimPathStart=".1"
android:trimPathEnd=".9"/>
</group>
- <animation android:sequence="arrow,house"/>
</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
index 137049d..1792683 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
@@ -71,67 +71,4 @@
android:fill="#ff88ff"
/>
</group>
- <group>
- <path
- android:name="clip1"
- android:pathData="
- M 0, 0
- l 7.3, 0
- l 0, 12.25
- l -7.3, 0
- z"
- android:clipToPath="true"
- android:rotation="-30"
- android:pivotX="3.65"
- android:pivotY="6.125"
- />
- <path
- android:name="one"
- android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
- l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
- l -5.046875,0.0 0.0,-1.0Z"
- android:fill="#ff88ff"
- />
- <path
- android:name="clip2"
- android:pathData="
- M 0, 12.25
- l 7.3, 0
- l 0, 12.25
- l -7.3, 0
- z"
- android:clipToPath="true"
- android:rotation="-30"
- android:pivotX="3.65"
- android:pivotY="6.125"
- />
- <path
- android:name="two"
- android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
- q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
- q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
- q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
- q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875
- q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
- q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
- q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
- q -0.78125024,0.8125 -2.2187502,2.265625Z"
- android:fill="#ff88ff"
- />
- </group>
-
-
- <animation
- android:sequence="one,one"
- android:durations="4000"/>
- <animation
- android:sequence="two,two"
- android:durations="4000"/>
- <animation
- android:sequence="clip1,clip1"
- android:durations="4000"/>
- <animation
- android:sequence="clip2,clip2"
- android:durations="4000"/>
-
</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
index cffb73f..90694fb 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
@@ -65,62 +65,4 @@
android:fill="#ff88ff"
/>
</group>
- <group>
- <path
- android:name="clip1"
- android:pathData="
- M 3.65, 6.125
- m -6, 0
- a 6,6 0 1,0 12,0
- a 6,6 0 1,0 -12,0z"
- android:clipToPath="true"
- android:fill="#332233"
- />
- <path
- android:name="one"
- android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
- l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
- l -5.046875,0.0 0.0,-1.0Z"
- android:fill="#ff88ff"
- />
- <path
- android:name="clip2"
- android:pathData="
- M 3.65, 6.125
- m -.001, 0
- a .001,.001 0 1,0 .002,0
- a .001,.001 0 1,0 -.002,0z"
- android:clipToPath="true"
- android:fill="#662233"
- />
- <path
- android:name="two"
- android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
- q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
- q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
- q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
- q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875
- q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
- q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
- q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
- q -0.78125024,0.8125 -2.2187502,2.265625Z"
- android:fill="#ff88ff"
- />
- </group>
-
-
-
- <animation
- android:sequence="one,one"
- android:durations="4000"/>
- <animation
- android:sequence="two,two"
- android:durations="4000"/>
- <animation
- android:sequence="clip1,clip1"
- android:durations="4000"/>
- <animation
- android:sequence="clip2,clip2"
- android:durations="4000"/>
-
</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
index 0be6755..c6595fa 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
@@ -44,95 +44,4 @@
q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
q -0.78125024,0.8125 -2.2187502,2.265625Z" />
</group>
- <group>
- <path
- android:name="one"
- android:fill="#ffff00"
- android:fillOpacity="0"
- android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
-l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
-l -5.046875,0.0 0.0,-1.0Z" />
- <path
- android:name="two"
- android:fill="#ffff00"
- android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
- q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
- q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
- q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
- q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875
- q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
- q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
- q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
- q -0.78125024,0.8125 -2.2187502,2.265625Z" />
- </group>
- <group>
- <path
- android:name="two"
- android:fill="#ffff00"
- android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
- q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
- q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
- q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
- q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875
- q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
- q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
- q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
- q -0.78125024,0.8125 -2.2187502,2.265625Z" />
- <path
- android:name="three"
- android:fill="#ffff00"
- android:fillOpacity="0"
- android:pathData="M 5.103125,6.003125q 0.84375,0.1875 1.3125,0.765625 0.484375,0.5625 0.484375,1.40625
- q 0.0,1.296875 -0.890625,2.015625 -0.890625,0.703125 -2.53125,0.703125
- q -0.546875,0.0 -1.140625,-0.109375 -0.5781251,-0.109375 -1.1875001,-0.328125
- l 0.0,-1.140625q 0.484375,0.28125 1.0625001,0.4375 0.59375,0.140625 1.234375,0.140625
- q 1.109375,0.0 1.6875,-0.4375 0.59375,-0.4375 0.59375,-1.28125
- q 0.0,-0.765625 -0.546875,-1.203125 -0.546875,-0.4375 -1.5,-0.4375
- l -1.03125,0.0 0.0,-0.96875 1.078125,0.0q 0.859375,0.0 1.328125,-0.34375
- q 0.46875,-0.359375 0.46875,-1.015625 0.0,-0.671875 -0.484375,-1.03125
- q -0.46875,-0.359375 -1.359375,-0.359375 -0.5,0.0 -1.0625,0.109375
- q -0.546875,0.09375 -1.2187501,0.3125l 0.0,-1.046875q 0.6875001,-0.1875 1.2656251,-0.28125
- q 0.59375,-0.09375 1.109375,-0.09375 1.359375,0.0 2.140625,0.609375
- q 0.78125,0.609375 0.78125,1.65625 0.0,0.734375 -0.421875,1.234375
- q -0.40625,0.5 -1.171875,0.6875Z" />
- </group>
- <group>
- <path
- android:name="two"
- android:fill="#ffff00"
- android:fillOpacity="0"
- android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
- q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
- q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
- q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
- q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875
- q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
- q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
- q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
- q -0.78125024,0.8125 -2.2187502,2.265625Z" />
- <path
- android:name="three"
- android:fill="#ffff00"
- android:pathData="M 5.103125,6.003125q 0.84375,0.1875 1.3125,0.765625 0.484375,0.5625 0.484375,1.40625
- q 0.0,1.296875 -0.890625,2.015625 -0.890625,0.703125 -2.53125,0.703125
- q -0.546875,0.0 -1.140625,-0.109375 -0.5781251,-0.109375 -1.1875001,-0.328125
- l 0.0,-1.140625q 0.484375,0.28125 1.0625001,0.4375 0.59375,0.140625 1.234375,0.140625
- q 1.109375,0.0 1.6875,-0.4375 0.59375,-0.4375 0.59375,-1.28125
- q 0.0,-0.765625 -0.546875,-1.203125 -0.546875,-0.4375 -1.5,-0.4375
- l -1.03125,0.0 0.0,-0.96875 1.078125,0.0q 0.859375,0.0 1.328125,-0.34375
- q 0.46875,-0.359375 0.46875,-1.015625 0.0,-0.671875 -0.484375,-1.03125
- q -0.46875,-0.359375 -1.359375,-0.359375 -0.5,0.0 -1.0625,0.109375
- q -0.546875,0.09375 -1.2187501,0.3125l 0.0,-1.046875q 0.6875001,-0.1875 1.2656251,-0.28125
- q 0.59375,-0.09375 1.109375,-0.09375 1.359375,0.0 2.140625,0.609375
- q 0.78125,0.609375 0.78125,1.65625 0.0,0.734375 -0.421875,1.234375
- q -0.40625,0.5 -1.171875,0.6875Z" />
- </group>
-
- <animation
- android:durations="2000,0,2000"
- android:sequence="one,one,three,three" />
- <animation
- android:durations="2000,0,2000"
- android:sequence="two,two,two,two" />
-
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
index 73ff5e2..850de28 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
@@ -23,29 +23,6 @@
android:viewportHeight="700"/>
<group>
- </group>
- <path android:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z"
- android:name="path2451"
- android:stroke="#FF000000"
- android:strokeWidth="30.65500000000000"/>
- <path android:pathData="M 365.015 311.066"
- android:name="path2453"
- android:stroke="#FF000000"
- android:strokeWidth="30.655000000000001"/>
- <path android:pathData="M 164.46 164.49L 340.78 343.158C 353.849 356.328 377.63 356.172 390.423 343.278L 566.622 165.928"
- android:name="path2455"
- android:stroke="#FF000000"
- android:fill="#FF0000FF"
- android:strokeWidth="30.655000000000001"/>
- <path android:pathData="M 170.515 451.566L 305.61 313.46"
- android:name="path2457"
- android:stroke="#000000"
- android:strokeWidth="30.655000000000001"/>
- <path android:pathData="M 557.968 449.974L 426.515 315.375"
- android:name="path2459"
- android:stroke="#000000"
- android:strokeWidth="30.655000000000001"/>
- <group>
<path android:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z"
android:name="path2451"
android:stroke="#FF000000"
@@ -68,9 +45,4 @@
android:stroke="#000000"
android:strokeWidth="30.655000000000001"/>
</group>
-
- <animation android:sequence="path2451,path2451"
- android:durations="1000"/>
-
-
</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
index 99d37ef..7c7e679 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
@@ -19,14 +19,7 @@
<viewport android:viewportWidth="140"
android:viewportHeight="110"/>
- <group>
- <path
- android:name="menu"
- android:pathData="M 20,20 l 100,0 0,10 -100,0 z
- M 20,50 l 100,0 0,10 -100,0 z
- M 20,80 l 0,-10 100,0 0,10 z"
- android:fill="#ffffffff"/>
- </group>
+
<group>
<path
android:name="back"
@@ -34,12 +27,6 @@
M 27,50 l 97,0 0,10 -97,0 z
M 20,55 l 7.07,-7.07 35.3,35.3 -7.07,7.07 z"
android:fill="#ffffffff"
- android:rotation="180"
- android:pivotX="70"
- android:pivotY="55"
/>
</group>
- <animation android:sequence="menu,back"/>
-
-
</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
index f8a03d7..59f7459 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
@@ -31,18 +31,4 @@
android:strokeWidth="1"/>
</group>
- <group>
- <path
- android:name="pie2"
- android:pathData="M564.441,287A280.868,280.868 0 1,1 564.441,285L284.493,286.29Z"
- android:fill="#FFccaa00"
- android:stroke="#FF000000"
- android:strokeWidth="10"
- android:pivotX="90"
- android:pivotY="100"/>
- </group>
-
- <animation android:sequence="pie1,pie2"/>
-
-
</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
index b3c91a88..2e379d6 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
@@ -25,12 +25,6 @@
<group>
<path
- android:name="arrow"
- android:fill="#ffffffff"
- android:pathData="M 20,20 l 60,0 0,140 -60,0 z M 120,20 l 60,0 0,140 -60,0 z" />
- </group>
- <group>
- <path
android:name="house"
android:fill="#ffffffff"
android:pathData="M 100,20 l 0,0 0,140 -80,0 z M 100,20 l 0,0 80,140 -80,0 z"
@@ -39,6 +33,4 @@
android:rotation="90" />
</group>
- <animation android:sequence="arrow,house" />
-
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
index 7aca169..8484e9e 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
@@ -21,8 +21,8 @@
android:width="64dp" />
<viewport
- android:viewportHeight="200"
- android:viewportWidth="200" />
+ android:viewportWidth="200"
+ android:viewportHeight="200"/>
<group>
<path
@@ -31,24 +31,6 @@
android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
<path
android:name="bar2"
- android:fill="#FF555555"
- android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
- <path
- android:name="bar1"
- android:fill="#FF555555"
- android:pathData="M14.001,34.645 L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
- <path
- android:name="bar0"
- android:fill="#FF555555"
- android:pathData="M0,20.502l6.999,7.071 c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
- </group>
- <group>
- <path
- android:name="bar3"
- android:fill="#FFFFFFFF"
- android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
- <path
- android:name="bar2"
android:fill="#FFFFFFFF"
android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
<path
@@ -60,54 +42,5 @@
android:fill="#FF555555"
android:pathData="M0,20.502l6.999,7.071 c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
</group>
- <group>
- <path
- android:name="bar3"
- android:fill="#FFFFFFFF"
- android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
- <path
- android:name="bar2"
- android:fill="#FFFFFFFF"
- android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
- <path
- android:name="bar1"
- android:fill="#FFFFFFFF"
- android:pathData="M14.001,34.645 L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
- <path
- android:name="bar0"
- android:fill="#FF555555"
- android:pathData="M0,20.502l6.999,7.071 c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
- </group>
- <group>
- <path
- android:name="bar3"
- android:fill="#FFFFFFFF"
- android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
- <path
- android:name="bar2"
- android:fill="#FFFFFFFF"
- android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
- <path
- android:name="bar1"
- android:fill="#FFFFFFFF"
- android:pathData="M14.001,34.645 L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
- <path
- android:name="bar0"
- android:fill="#FFFFFFFF"
- android:pathData="M0,20.502l6.999,7.071 c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
- </group>
-
- <animation
- android:durations="500,500,500"
- android:sequence="bar0,bar0,bar0,bar0" />
- <animation
- android:durations="500,500,500"
- android:sequence="bar1,bar1,bar1,bar1" />
- <animation
- android:durations="500,500,500"
- android:sequence="bar2,bar2,bar2,bar2" />
- <animation
- android:durations="500,500,500"
- android:sequence="bar3,bar3,bar3,bar3" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
index a4403c5..2b6c5d3 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
@@ -36,25 +36,5 @@
android:fill="#FFFF0000"
android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
</group>
- <group>
- <path
- android:name="battery"
- android:fill="#ff8833"
- android:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
- android:rotation="0"
- android:stroke="#3388ff"
- android:strokeWidth="1" />
- <path
- android:name="spark"
- android:fill="#FFFF0000"
- android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
- </group>
-
- <animation
- android:durations="2000"
- android:sequence="spark,spark" />
- <animation
- android:durations="2000"
- android:sequence="battery,battery" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
index 207879d..681eb4f 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
@@ -40,48 +40,5 @@
android:pivotY="300"
android:rotation="0" />
</group>
- <group>
- <path
- android:name="v"
- android:pathData="M300,70 l 0,-70 70,70 -70,70z"
- android:pivotX="300"
- android:pivotY="300"
- android:rotation="360" />
- <path
- android:name="pie2"
- android:pathData="M300,70 a230,230 0 1,0 1,0 z"
- android:pivotX="300"
- android:pivotY="300"
- android:rotation="360"
- android:stroke="#FF00FF00"
- android:strokeLineCap="round"
- android:strokeWidth="70"
- android:trimPathEnd=".5"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- </group>
-
- <animation
- android:animate="easeInOut"
- android:durations="2000"
- android:repeatCount="-1"
- android:repeatStyle="forward"
- android:sequence="pie1,pie2"
- android:startOffset="500" />
- <animation
- android:animate="easeInOut"
- android:durations="2000"
- android:repeatCount="-1"
- android:repeatStyle="forward"
- android:sequence="v,v"
- android:startOffset="500" />
- <animation
- android:animate="easeInOut"
- android:durations="2800"
- android:limitTo="trimPathEnd"
- android:repeatCount="-1"
- android:repeatStyle="reverse"
- android:sequence="pie1,pie2"
- android:startOffset="500" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
index 4a2ed90..ef1b8e4 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
@@ -40,40 +40,5 @@
android:stroke="#FF0000FF"
android:strokeWidth="5" />
</group>
- <group>
- <path
- android:name="pie2"
- android:fill="#ffff0000"
- android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
- android:pivotX="300"
- android:pivotY="200"
- android:rotation="360"
- android:stroke="#FF00FF00"
- android:strokeWidth="10" />
- <path
- android:name="half"
- android:fill="#FFFFFF00"
- android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
- android:pivotX="300"
- android:pivotY="200"
- android:rotation="-360"
- android:stroke="#FF0000FF"
- android:strokeWidth="5" />
- </group>
-
- <animation
- android:animate="easeInOut"
- android:durations="1000"
- android:repeatCount="2"
- android:repeatStyle="forward"
- android:sequence="pie1,pie2"
- android:startOffset="500" />
- <animation
- android:animate="easeInOut"
- android:durations="1000"
- android:repeatCount="5"
- android:repeatStyle="forward"
- android:sequence="half,half"
- android:startOffset="500" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
index 6ebd56b..77bf723 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
@@ -25,17 +25,6 @@
<group>
<path
- android:name="pie1"
- android:pathData="M200,450 l 50,-25
- a25,25 -30 0,1 100,-50 l 50,-25
- a25,50 -30 0,1 100,-50 l 50,-25
- a25,75 -30 0,1 100,-50 l 50,-25
- a25,100 -30 0,1 100,-50 l 50,-25"
- android:stroke="#FF00FF00"
- android:strokeWidth="10" />
- </group>
- <group>
- <path
android:name="pie2"
android:pathData="M200,350 l 50,-25
a25,12 -30 0,1 100,-50 l 50,-25
@@ -49,6 +38,4 @@
android:strokeWidth="10" />
</group>
- <animation android:sequence="pie1,pie2" />
-
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
index 3c92d25..df5838c 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
@@ -25,14 +25,6 @@
<group>
<path
- android:name="arrow"
- android:fill="#ffffffff"
- android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
- android:stroke="#FFFF0000"
- android:strokeWidth="1" />
- </group>
- <group>
- <path
android:name="house"
android:fill="#ff440000"
android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
@@ -43,6 +35,4 @@
android:strokeWidth="10" />
</group>
- <animation android:sequence="arrow,house" />
-
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
index 7e757a5..0bdcda5 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
@@ -25,13 +25,6 @@
<group>
<path
- android:name="arrow"
- android:pathData="M 100,10 v 180 M 10,100 h 180"
- android:stroke="#FF00FF00"
- android:strokeWidth="1" />
- </group>
- <group>
- <path
android:name="house"
android:pathData="M 100,10 v 90 M 10,100 h 90"
android:pivotX="100"
@@ -41,6 +34,4 @@
android:strokeWidth="10" />
</group>
- <animation android:sequence="arrow,house" />
-
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
index 9427652..4453ae4 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
@@ -23,14 +23,6 @@
<group>
<path
- android:name="arrow"
- android:pathData="M200,300 Q400,50 600,300 T1000,300"
- android:stroke="#FF00FF00"
- android:strokeWidth="1"/>
- </group>
-
- <group>
- <path
android:name="house"
android:pathData="M200,300 Q400,50 600,300 T1000,300"
android:stroke="#FFFF0000"
@@ -40,7 +32,4 @@
android:pivotY="300"/>
</group>
- <animation android:sequence="arrow,house"/>
-
-
</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
index 69212f5..dfae9ac 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
@@ -25,21 +25,13 @@
<group>
<path
- android:name="arrow"
- android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
- android:stroke="#FFFFFF00"
- android:strokeWidth="10" />
- </group>
- <group>
- <path
android:name="house"
android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
android:pivotX="250"
android:pivotY="200"
android:rotation="360"
+ android:stroke="#FFFFFF00"
android:strokeWidth="10" />
</group>
- <animation android:sequence="arrow,house" />
-
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
index 2dca48d..a890fd6 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
@@ -25,13 +25,6 @@
<group>
<path
- android:name="arrow"
- android:pathData="M10,300 Q400,50 600,300 T1000,300"
- android:stroke="#FF00FFFF"
- android:strokeWidth="40" />
- </group>
- <group>
- <path
android:name="house"
android:pathData="M10,300 Q400,550 600,300 T1000,300"
android:pivotX="90"
@@ -40,6 +33,4 @@
android:strokeWidth="60" />
</group>
- <animation android:sequence="arrow,house" />
-
</vector>
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index bb05d45..aede236 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -71,7 +71,7 @@
* Returns the native delegate associated to a given {@link Canvas} object.
*/
public static Canvas_Delegate getDelegate(Canvas canvas) {
- return sManager.getDelegate(canvas.mNativeCanvas);
+ return sManager.getDelegate(canvas.getNativeCanvas());
}
/**
@@ -102,7 +102,7 @@
@LayoutlibDelegate
/*package*/ static boolean isOpaque(Canvas thisCanvas) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return false;
}
@@ -113,7 +113,7 @@
@LayoutlibDelegate
/*package*/ static int getWidth(Canvas thisCanvas) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return 0;
}
@@ -124,7 +124,7 @@
@LayoutlibDelegate
/*package*/ static int getHeight(Canvas thisCanvas) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return 0;
}
@@ -135,7 +135,7 @@
@LayoutlibDelegate
/*package*/ static void translate(Canvas thisCanvas, float dx, float dy) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return;
}
@@ -146,7 +146,7 @@
@LayoutlibDelegate
/*package*/ static void rotate(Canvas thisCanvas, float degrees) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return;
}
@@ -157,7 +157,7 @@
@LayoutlibDelegate
/*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return;
}
@@ -168,7 +168,7 @@
@LayoutlibDelegate
/*package*/ static void skew(Canvas thisCanvas, float kx, float ky) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return;
}
@@ -204,7 +204,7 @@
/*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right,
float bottom) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return false;
}
@@ -227,7 +227,7 @@
@LayoutlibDelegate
/*package*/ static int save(Canvas thisCanvas, int saveFlags) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return 0;
}
@@ -238,7 +238,7 @@
@LayoutlibDelegate
/*package*/ static void restore(Canvas thisCanvas) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return;
}
@@ -249,7 +249,7 @@
@LayoutlibDelegate
/*package*/ static int getSaveCount(Canvas thisCanvas) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return 0;
}
@@ -260,7 +260,7 @@
@LayoutlibDelegate
/*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return;
}
@@ -287,7 +287,7 @@
/*package*/ static void drawLines(Canvas thisCanvas,
final float[] pts, final int offset, final int count,
Paint paint) {
- draw(thisCanvas.mNativeCanvas, paint.mNativePaint, false /*compositeOnly*/,
+ draw(thisCanvas.getNativeCanvas(), paint.mNativePaint, false /*compositeOnly*/,
false /*forceSrcMode*/, new GcSnapshot.Drawable() {
@Override
public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
diff --git a/core/res/res/drawable/stat_sys_adb.xml b/wifi/java/android/net/wifi/IWifiScanner.aidl
similarity index 61%
rename from core/res/res/drawable/stat_sys_adb.xml
rename to wifi/java/android/net/wifi/IWifiScanner.aidl
index dfc8563..fef2d11 100644
--- a/core/res/res/drawable/stat_sys_adb.xml
+++ b/wifi/java/android/net/wifi/IWifiScanner.aidl
@@ -1,13 +1,11 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
/*
- * Copyright 2013, The Android Open Source Project
+ * Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -15,9 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
--->
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/stat_sys_adb_am"
- android:autoMirrored="true">
-</bitmap>
+package android.net.wifi;
+
+import android.os.Messenger;
+
+/**
+ * {@hide}
+ */
+interface IWifiScanner
+{
+ Messenger getMessenger();
+}
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index d7ecaff..1cb9546 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -56,6 +56,13 @@
public long timestamp;
/**
+ * Timestamp representing date when this result was last seen, in milliseconds from 1970
+ * {@hide}
+ */
+ public long seen;
+
+
+ /**
* The approximate distance to the AP in centimeter, if available. Else
* {@link UNSPECIFIED}.
* {@hide}
@@ -114,9 +121,17 @@
timestamp = source.timestamp;
distanceCm = source.distanceCm;
distanceSdCm = source.distanceSdCm;
+ seen = source.seen;
}
}
+ /** empty scan result
+ *
+ * {@hide}
+ * */
+ public ScanResult() {
+ }
+
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 6562462..ce8c8b8 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -21,6 +21,7 @@
import android.os.Parcel;
import android.text.TextUtils;
+import java.util.HashMap;
import java.util.BitSet;
/**
@@ -302,6 +303,156 @@
/**
* @hide
+ * dhcp server MAC address if known
+ */
+ public String dhcpServer;
+
+ /**
+ * @hide
+ * default Gateway MAC address if known
+ */
+ public String defaultGwMacAddress;
+
+ /**
+ * @hide
+ * BSSID list on which this configuration was seen.
+ * TODO: prevent this list to grow infinitely, age-out the results
+ */
+ public HashMap<String, ScanResult> scanResultCache;
+
+ /** @hide **/
+ public static int INVALID_RSSI = -127;
+
+ /**
+ * @hide
+ * A summary of the RSSI and Band status for that configuration
+ * This is used as a temporary value by the auto-join controller
+ */
+ public final class Visibility
+ {
+ public int rssi5; // strongest 5GHz RSSI
+ public int rssi24; // strongest 2.4GHz RSSI
+ public int num5; // number of BSSIDs on 5GHz
+ public int num24; // number of BSSIDs on 2.4GHz
+ public long age5; // timestamp of the strongest 5GHz BSSID (last time it was seen)
+ public long age24; // timestamp of the strongest 2.4GHz BSSID (last time it was seen)
+ public Visibility()
+ {
+ rssi5 = INVALID_RSSI;
+ rssi24 = INVALID_RSSI;
+ }
+ public Visibility(Visibility source)
+ {
+ rssi5 = source.rssi5;
+ rssi24 = source.rssi24;
+ age24 = source.age24;
+ age5 = source.age5;
+ num24 = source.num24;
+ num5 = source.num5;
+ }
+ }
+
+ /** @hide
+ * Cache the visibility status of this configuration.
+ * Visibility can change at any time depending on scan results availability.
+ * Owner of the WifiConfiguration is responsible to set this field based on
+ * recent scan results.
+ ***/
+ public Visibility visibility;
+
+ /** @hide
+ * calculate and set Visibility for that configuration.
+ *
+ * age in milliseconds: we will consider only ScanResults that are more recent,
+ * i.e. younger.
+ ***/
+ public Visibility setVisibility(long age) {
+ if (scanResultCache == null) {
+ visibility = null;
+ return null;
+ }
+
+ Visibility status = new Visibility();
+
+ long now_ms = System.currentTimeMillis();
+ for(ScanResult result : scanResultCache.values()) {
+ if (result.seen == 0)
+ continue;
+
+ if ((result.frequency > 4900) && (result.frequency < 5900)) {
+ //strictly speaking: [4915, 5825]
+ //number of known BSSID on 5GHz band
+ status.num5 = status.num5 + 1;
+ } else if ((result.frequency > 2400) && (result.frequency < 2500)) {
+ //strictly speaking: [2412, 2482]
+ //number of known BSSID on 2.4Ghz band
+ status.num24 = status.num24 + 1;
+ }
+
+ if ((now_ms - result.seen) > age) continue;
+
+ if ((result.frequency > 4900) && (result.frequency < 5900)) {
+ if (result.level > status.rssi5) {
+ status.rssi5 = result.level;
+ status.age5 = result.seen;
+ }
+ } else if ((result.frequency > 2400) && (result.frequency < 2500)) {
+ if (result.level > status.rssi24) {
+ status.rssi24 = result.level;
+ status.age24 = result.seen;
+ }
+ }
+ }
+ visibility = status;
+ return status;
+ }
+
+ /** @hide */
+ public static final int AUTO_JOIN_ENABLED = 0;
+ /** @hide */
+ public static final int AUTO_JOIN_DISABLED_ON_AUTH_FAILURE = 1;
+ /**
+ * @hide
+ */
+ public int autoJoinStatus;
+
+ /**
+ * @hide
+ * Indicate that a WifiConfiguration is temporary and should not be saved
+ * nor considered by AutoJoin.
+ */
+ public boolean ephemeral;
+
+ /**
+ * @hide
+ * Connect choices
+ *
+ * remember the keys identifying the known WifiConfiguration over which this configuration
+ * was preferred by user or a "WiFi Network Management app", that is,
+ * a WifiManager.CONNECT_NETWORK or SELECT_NETWORK was received while this configuration
+ * was visible to the user:
+ * configKey is : "SSID"-WEP-WPA_PSK-WPA_EAP
+ *
+ * The integer represents the configuration's RSSI at that time (useful?)
+ *
+ * The overall auto-join algorithm make use of past connect choice so as to sort configuration,
+ * the exact algorithm still fluctuating as of 5/7/2014
+ *
+ */
+ public HashMap<String, Integer> connectChoices;
+
+ /**
+ * @hide
+ * Linked Configurations: represent the set of Wificonfigurations that are equivalent
+ * regarding roaming and auto-joining.
+ * The linked configuration may or may not have same SSID, and may or may not have same
+ * credentials.
+ * For instance, linked configurations will have same defaultGwMacAddress or same dhcp server.
+ */
+ public HashMap<String, Integer> linkedConfigurations;
+
+ /**
+ * @hide
*/
public enum ProxySettings {
/* No proxy is to be used. Any existing proxy settings
@@ -346,6 +497,7 @@
ipAssignment = IpAssignment.UNASSIGNED;
proxySettings = ProxySettings.UNASSIGNED;
linkProperties = new LinkProperties();
+ autoJoinStatus = AUTO_JOIN_ENABLED;
}
/**
@@ -369,6 +521,32 @@
// TODO: Add more checks
return true;
+
+ }
+
+ /**
+ * most recent time we have seen this configuration
+ * @return most recent scanResult
+ * @hide
+ */
+ public ScanResult lastSeen() {
+ ScanResult mostRecent = null;
+
+ if (scanResultCache == null) {
+ return null;
+ }
+
+ for (ScanResult result : scanResultCache.values()) {
+ if (mostRecent == null) {
+ if (result.seen != 0)
+ mostRecent = result;
+ } else {
+ if (result.seen > mostRecent.seen) {
+ mostRecent = result;
+ }
+ }
+ }
+ return mostRecent;
}
@Override
@@ -570,7 +748,48 @@
return KeyMgmt.NONE;
}
- /** Implement the Parcelable interface {@hide} */
+ /* @hide
+ * Cache the config key, this seems useful as a speed up since a lot of
+ * lookups in the config store are done and based on this key.
+ */
+ String mCachedConfigKey;
+
+ /** @hide
+ * return the string used to calculate the hash in WifiConfigStore
+ * and uniquely identify this WifiConfiguration
+ */
+ public String configKey(boolean allowCached) {
+ String key;
+ if (allowCached && mCachedConfigKey != null) {
+ key = mCachedConfigKey;
+ } else {
+ key = this.SSID;
+ if (key == null)
+ key = "";
+ if (this.wepKeys[0] != null) {
+ key = key + "-WEP";
+ }
+ if (this.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
+ key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_PSK];
+ }
+ if (this.allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
+ this.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
+ key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_EAP];
+ }
+ mCachedConfigKey = key;
+ }
+ return key;
+ }
+
+ /** @hide
+ * get configKey, force calculating the config string
+ */
+ public String configKey() {
+ return configKey(false);
+ }
+
+
+ /** Implement the Parcelable interface {@hide} */
public int describeContents() {
return 0;
}
@@ -603,8 +822,32 @@
ipAssignment = source.ipAssignment;
proxySettings = source.proxySettings;
+
+ defaultGwMacAddress = source.defaultGwMacAddress;
+
linkProperties = new LinkProperties(source.linkProperties);
- }
+ if ((source.scanResultCache != null) && (source.scanResultCache.size() > 0)) {
+ scanResultCache = new HashMap<String, ScanResult>();
+ scanResultCache.putAll(source.scanResultCache);
+ }
+
+ if ((source.connectChoices != null) && (source.connectChoices.size() > 0)) {
+ connectChoices = new HashMap<String, Integer>();
+ connectChoices.putAll(source.connectChoices);
+ }
+
+ if ((source.linkedConfigurations != null)
+ && (source.linkedConfigurations.size() > 0)) {
+ linkedConfigurations = new HashMap<String, Integer>();
+ linkedConfigurations.putAll(source.linkedConfigurations);
+ }
+ mCachedConfigKey = null; //force null configKey
+ autoJoinStatus = source.autoJoinStatus;
+
+ if (source.visibility != null) {
+ visibility = new Visibility(source.visibility);
+ }
+ }
}
/** Implement the Parcelable interface {@hide} */
@@ -633,6 +876,10 @@
dest.writeString(ipAssignment.name());
dest.writeString(proxySettings.name());
dest.writeParcelable(linkProperties, flags);
+
+ dest.writeString(dhcpServer);
+ dest.writeString(defaultGwMacAddress);
+ dest.writeInt(autoJoinStatus);
}
/** Implement the Parcelable interface {@hide} */
@@ -664,6 +911,10 @@
config.proxySettings = ProxySettings.valueOf(in.readString());
config.linkProperties = in.readParcelable(null);
+ config.dhcpServer = in.readString();
+ config.defaultGwMacAddress = in.readString();
+ config.autoJoinStatus = in.readInt();
+
return config;
}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
new file mode 100644
index 0000000..e02e14c
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+
+/**
+ * This class provides a way to scan the Wifi universe around the device
+ * Get an instance of this class by calling
+ * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context
+ * .WIFI_SCANNING_SERVICE)}.
+ * @hide
+ */
+public class WifiScanner {
+
+ public static final int WIFI_BAND_UNSPECIFIED = 0; /* not specified */
+ public static final int WIFI_BAND_24_GHZ = 1; /* 2.4 GHz band */
+ public static final int WIFI_BAND_5_GHZ = 2; /* 5 GHz band without DFS channels */
+ public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 4; /* 5 GHz band with DFS channels */
+ public static final int WIFI_BAND_5_GHZ_WITH_DFS = 6; /* 5 GHz band with DFS channels */
+ public static final int WIFI_BAND_BOTH = 3; /* both bands without DFS channels */
+ public static final int WIFI_BAND_BOTH_WITH_DFS = 7; /* both bands with DFS channels */
+
+ public static final int MIN_SCAN_PERIOD_MS = 300; /* minimum supported period */
+ public static final int MAX_SCAN_PERIOD_MS = 1024000; /* maximum supported period */
+
+ public static final int REASON_SUCCEEDED = 0;
+ public static final int REASON_UNSPECIFIED = -1;
+ public static final int REASON_INVALID_LISTENER = -2;
+ public static final int REASON_INVALID_REQUEST = -3;
+ public static final int REASON_CONFLICTING_REQUEST = -4;
+
+ public static interface ActionListener {
+ public void onSuccess(Object result);
+ public void onFailure(int reason, Object exception);
+ }
+
+ /**
+ * gives you all the possible channels; channel is specified as an
+ * integer with frequency in MHz i.e. channel 1 is 2412
+ */
+ public List<Integer> getAvailableChannels(int band) {
+ return null;
+ }
+
+ /**
+ * provides channel specification to the APIs
+ */
+ public static class ChannelSpec {
+ public int frequency;
+ public boolean passive; /* ignored on DFS channels */
+ public int dwellTimeMS; /* not supported for now */
+
+ public ChannelSpec(int frequency) {
+ this.frequency = frequency;
+ passive = false;
+ dwellTimeMS = 0;
+ }
+ }
+
+ public static final int REPORT_EVENT_AFTER_BUFFER_FULL = 0;
+ public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1;
+ public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2;
+
+ /**
+ * scan configuration parameters
+ */
+ public static class ScanSettings implements Parcelable {
+
+ public int band; /* ignore channels if specified */
+ public ChannelSpec[] channels; /* list of channels to scan */
+ public int periodInMs; /* period of scan */
+ public int reportEvents; /* a valid REPORT_EVENT value */
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(band);
+ dest.writeInt(periodInMs);
+ dest.writeInt(channels.length);
+
+ for (int i = 0; i < channels.length; i++) {
+ dest.writeInt(channels[i].frequency);
+ dest.writeInt(channels[i].dwellTimeMS);
+ dest.writeInt(channels[i].passive ? 1 : 0);
+ }
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<ScanSettings> CREATOR =
+ new Creator<ScanSettings>() {
+ public ScanSettings createFromParcel(Parcel in) {
+
+ ScanSettings settings = new ScanSettings();
+ settings.band = in.readInt();
+ settings.periodInMs = in.readInt();
+ int num_channels = in.readInt();
+ settings.channels = new ChannelSpec[num_channels];
+ for (int i = 0; i < num_channels; i++) {
+ int frequency = in.readInt();
+
+ ChannelSpec spec = new ChannelSpec(frequency);
+ spec.dwellTimeMS = in.readInt();
+ spec.passive = in.readInt() == 1;
+ settings.channels[i] = spec;
+ }
+
+ return settings;
+ }
+
+ public ScanSettings[] newArray(int size) {
+ return new ScanSettings[size];
+ }
+ };
+
+ }
+
+ public static class InformationElement {
+ public int id;
+ public byte[] bytes;
+ }
+
+ public static class FullScanResult {
+ public ScanResult result;
+ public InformationElement informationElements[];
+ }
+
+ /** @hide */
+ public static class ParcelableScanResults implements Parcelable {
+ public ScanResult mResults[];
+
+ public ParcelableScanResults(ScanResult[] results) {
+ mResults = results;
+ }
+
+ public ScanResult[] getResults() {
+ return mResults;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mResults.length);
+ for (int i = 0; i < mResults.length; i++) {
+ ScanResult result = mResults[i];
+ result.writeToParcel(dest, flags);
+ }
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<ParcelableScanResults> CREATOR =
+ new Creator<ParcelableScanResults>() {
+ public ParcelableScanResults createFromParcel(Parcel in) {
+ int n = in.readInt();
+ ScanResult results[] = new ScanResult[n];
+ for (int i = 0; i < n; i++) {
+ results[i] = ScanResult.CREATOR.createFromParcel(in);
+ }
+ return new ParcelableScanResults(results);
+ }
+
+ public ParcelableScanResults[] newArray(int size) {
+ return new ParcelableScanResults[size];
+ }
+ };
+ }
+
+ /**
+ * Framework is co-ordinating scans across multiple apps; so it may not give exactly the
+ * same period requested. The period granted is stated on the onSuccess() event; and
+ * onPeriodChanged() will be called if/when it is changed because of multiple conflicting
+ * requests. This is similar to the way timers are handled.
+ */
+ public interface ScanListener extends ActionListener {
+ public void onPeriodChanged(int periodInMs);
+ public void onResults(ScanResult[] results);
+ public void onFullResult(FullScanResult fullScanResult);
+ }
+
+ public void scan(ScanSettings settings, ScanListener listener) {
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_SCAN, 0, putListener(listener), settings);
+ }
+ public void startBackgroundScan(ScanSettings settings, ScanListener listener) {
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, putListener(listener), settings);
+ }
+ public void stopBackgroundScan(boolean flush, ScanListener listener) {
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, removeListener(listener));
+ }
+ public void retrieveScanResults(boolean flush, ScanListener listener) {
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_GET_SCAN_RESULTS, 0, getListenerKey(listener));
+ }
+
+ public static class HotspotInfo {
+ public String bssid;
+ public int low; /* minimum RSSI */
+ public int high; /* maximum RSSI */
+ }
+
+ public static class WifiChangeSettings {
+ public int rssiSampleSize; /* sample size for RSSI averaging */
+ public int lostApSampleSize; /* samples to confirm AP's loss */
+ public int unchangedSampleSize; /* samples to confirm no change */
+ public int minApsBreachingThreshold; /* change threshold to trigger event */
+ public HotspotInfo[] hotspotInfos;
+ }
+
+ /* overrides the significant wifi change state machine configuration */
+ public void configureSignificantWifiChange(
+ int rssiSampleSize, /* sample size for RSSI averaging */
+ int lostApSampleSize, /* samples to confirm AP's loss */
+ int unchangedSampleSize, /* samples to confirm no change */
+ int minApsBreachingThreshold, /* change threshold to trigger event */
+ HotspotInfo[] hotspotInfos /* signal thresholds to crosss */
+ )
+ {
+ validateChannel();
+ WifiChangeSettings settings = new WifiChangeSettings();
+ settings.rssiSampleSize = rssiSampleSize;
+ settings.lostApSampleSize = lostApSampleSize;
+ settings.unchangedSampleSize = unchangedSampleSize;
+ settings.minApsBreachingThreshold = minApsBreachingThreshold;
+ settings.hotspotInfos = hotspotInfos;
+
+ sAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
+ }
+
+ public interface SignificantWifiChangeListener extends ActionListener {
+ public void onChanging(ScanResult[] results); /* changes are found */
+ public void onQuiescence(ScanResult[] results); /* changes settled down */
+ }
+
+ public void trackSignificantWifiChange(SignificantWifiChangeListener listener) {
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, putListener(listener));
+ }
+ public void untrackSignificantWifiChange(SignificantWifiChangeListener listener) {
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, removeListener(listener));
+ }
+
+ public void configureSignificantWifiChange(WifiChangeSettings settings) {
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
+ }
+
+ public static interface HotlistListener extends ActionListener {
+ public void onFound(ScanResult[] results);
+ }
+
+ /** @hide */
+ public static class HotlistSettings implements Parcelable {
+ public HotspotInfo[] hotspotInfos;
+ public int apLostThreshold;
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(apLostThreshold);
+ dest.writeInt(hotspotInfos.length);
+ for (int i = 0; i < hotspotInfos.length; i++) {
+ HotspotInfo info = hotspotInfos[i];
+ dest.writeString(info.bssid);
+ dest.writeInt(info.low);
+ dest.writeInt(info.high);
+ }
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<HotlistSettings> CREATOR =
+ new Creator<HotlistSettings>() {
+ public HotlistSettings createFromParcel(Parcel in) {
+ HotlistSettings settings = new HotlistSettings();
+ settings.apLostThreshold = in.readInt();
+ int n = in.readInt();
+ settings.hotspotInfos = new HotspotInfo[n];
+ for (int i = 0; i < n; i++) {
+ HotspotInfo info = new HotspotInfo();
+ info.bssid = in.readString();
+ info.low = in.readInt();
+ info.high = in.readInt();
+ settings.hotspotInfos[i] = info;
+ }
+ return settings;
+ }
+
+ public HotlistSettings[] newArray(int size) {
+ return new HotlistSettings[size];
+ }
+ };
+ }
+
+ public void setHotlist(HotspotInfo[] hotspots,
+ int apLostThreshold, HotlistListener listener) {
+ validateChannel();
+ HotlistSettings settings = new HotlistSettings();
+ settings.hotspotInfos = hotspots;
+ sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, putListener(listener), settings);
+ }
+
+ public void resetHotlist(HotlistListener listener) {
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, removeListener(listener));
+ }
+
+
+ /* private members and methods */
+
+ private static final String TAG = "WifiScanner";
+ private static final boolean DBG = true;
+
+ /* commands for Wifi Service */
+ private static final int BASE = Protocol.BASE_WIFI_SCANNER;
+
+ /** @hide */
+ public static final int CMD_SCAN = BASE + 0;
+ /** @hide */
+ public static final int CMD_START_BACKGROUND_SCAN = BASE + 2;
+ /** @hide */
+ public static final int CMD_STOP_BACKGROUND_SCAN = BASE + 3;
+ /** @hide */
+ public static final int CMD_GET_SCAN_RESULTS = BASE + 4;
+ /** @hide */
+ public static final int CMD_SCAN_RESULT = BASE + 5;
+ /** @hide */
+ public static final int CMD_SET_HOTLIST = BASE + 6;
+ /** @hide */
+ public static final int CMD_RESET_HOTLIST = BASE + 7;
+ /** @hide */
+ public static final int CMD_AP_FOUND = BASE + 9;
+ /** @hide */
+ public static final int CMD_AP_LOST = BASE + 10;
+ /** @hide */
+ public static final int CMD_START_TRACKING_CHANGE = BASE + 11;
+ /** @hide */
+ public static final int CMD_STOP_TRACKING_CHANGE = BASE + 12;
+ /** @hide */
+ public static final int CMD_CONFIGURE_WIFI_CHANGE = BASE + 13;
+ /** @hide */
+ public static final int CMD_WIFI_CHANGE_DETECTED = BASE + 15;
+ /** @hide */
+ public static final int CMD_WIFI_CHANGES_STABILIZED = BASE + 16;
+ /** @hide */
+ public static final int CMD_OP_SUCCEEDED = BASE + 17;
+ /** @hide */
+ public static final int CMD_OP_FAILED = BASE + 18;
+ /** @hide */
+ public static final int CMD_PERIOD_CHANGED = BASE + 19;
+ /** @hide */
+ public static final int CMD_FULL_SCAN_RESULT = BASE + 20;
+
+ private Context mContext;
+ private IWifiScanner mService;
+
+ private static final int INVALID_KEY = 0;
+ private static int sListenerKey = 1;
+
+ private static final SparseArray sListenerMap = new SparseArray();
+ private static final Object sListenerMapLock = new Object();
+
+ private static AsyncChannel sAsyncChannel;
+ private static CountDownLatch sConnected;
+
+ private static final Object sThreadRefLock = new Object();
+ private static int sThreadRefCount;
+ private static HandlerThread sHandlerThread;
+
+ /**
+ * Create a new WifiScanner instance.
+ * Applications will almost always want to use
+ * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
+ * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
+ * @param context the application context
+ * @param service the Binder interface
+ * @hide
+ */
+ public WifiScanner(Context context, IWifiScanner service) {
+ mContext = context;
+ mService = service;
+ init();
+ }
+
+ private void init() {
+ synchronized (sThreadRefLock) {
+ if (++sThreadRefCount == 1) {
+ Messenger messenger = null;
+ try {
+ messenger = mService.getMessenger();
+ } catch (RemoteException e) {
+ /* do nothing */
+ } catch (SecurityException e) {
+ /* do nothing */
+ }
+
+ if (messenger == null) {
+ sAsyncChannel = null;
+ return;
+ }
+
+ sHandlerThread = new HandlerThread("WifiScanner");
+ sAsyncChannel = new AsyncChannel();
+ sConnected = new CountDownLatch(1);
+
+ sHandlerThread.start();
+ Handler handler = new ServiceHandler(sHandlerThread.getLooper());
+ sAsyncChannel.connect(mContext, handler, messenger);
+ try {
+ sConnected.await();
+ } catch (InterruptedException e) {
+ Log.e(TAG, "interrupted wait at init");
+ }
+ }
+ }
+ }
+
+ private void validateChannel() {
+ if (sAsyncChannel == null) throw new IllegalStateException(
+ "No permission to access and change wifi or a bad initialization");
+ }
+
+ private static int putListener(Object listener) {
+ if (listener == null) return INVALID_KEY;
+ int key;
+ synchronized (sListenerMapLock) {
+ do {
+ key = sListenerKey++;
+ } while (key == INVALID_KEY);
+ sListenerMap.put(key, listener);
+ }
+ return key;
+ }
+
+ private static Object getListener(int key) {
+ if (key == INVALID_KEY) return null;
+ synchronized (sListenerMapLock) {
+ Object listener = sListenerMap.get(key);
+ return listener;
+ }
+ }
+
+ private static int getListenerKey(Object listener) {
+ if (listener == null) return INVALID_KEY;
+ synchronized (sListenerMapLock) {
+ int index = sListenerMap.indexOfValue(listener);
+ if (index == -1) {
+ return INVALID_KEY;
+ } else {
+ return sListenerMap.keyAt(index);
+ }
+ }
+ }
+
+ private static Object removeListener(int key) {
+ if (key == INVALID_KEY) return null;
+ synchronized (sListenerMapLock) {
+ Object listener = sListenerMap.get(key);
+ sListenerMap.remove(key);
+ return listener;
+ }
+ }
+
+ private static int removeListener(Object listener) {
+ int key = getListenerKey(listener);
+ if (key == INVALID_KEY) return key;
+ synchronized (sListenerMapLock) {
+ sListenerMap.remove(key);
+ return key;
+ }
+ }
+
+ private static class ServiceHandler extends Handler {
+ ServiceHandler(Looper looper) {
+ super(looper);
+ }
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
+ if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+ sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+ } else {
+ Log.e(TAG, "Failed to set up channel connection");
+ // This will cause all further async API calls on the WifiManager
+ // to fail and throw an exception
+ sAsyncChannel = null;
+ }
+ sConnected.countDown();
+ return;
+ case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
+ return;
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
+ Log.e(TAG, "Channel connection lost");
+ // This will cause all further async API calls on the WifiManager
+ // to fail and throw an exception
+ sAsyncChannel = null;
+ getLooper().quit();
+ return;
+ }
+
+ Object listener = getListener(msg.arg2);
+ if (DBG) Log.d(TAG, "listener key = " + msg.arg2);
+
+ switch (msg.what) {
+ /* ActionListeners grouped together */
+ case CMD_OP_SUCCEEDED :
+ ((ActionListener) listener).onSuccess(msg.obj);
+ break;
+ case CMD_OP_FAILED :
+ ((ActionListener) listener).onFailure(msg.arg1, msg.obj);
+ break;
+ case CMD_SCAN_RESULT :
+ ((ScanListener) listener).onResults(
+ ((ParcelableScanResults) msg.obj).getResults());
+ return;
+ case CMD_FULL_SCAN_RESULT :
+ FullScanResult result = (FullScanResult) msg.obj;
+ ((ScanListener) listener).onFullResult(result);
+ return;
+ case CMD_AP_FOUND:
+ ((HotlistListener) listener).onFound(
+ ((ParcelableScanResults) msg.obj).getResults());
+ return;
+ case CMD_WIFI_CHANGE_DETECTED:
+ ((SignificantWifiChangeListener) listener).onChanging(
+ ((ParcelableScanResults) msg.obj).getResults());
+ return;
+ case CMD_WIFI_CHANGES_STABILIZED:
+ ((SignificantWifiChangeListener) listener).onQuiescence(
+ ((ParcelableScanResults) msg.obj).getResults());
+ return;
+ default:
+ if (DBG) Log.d(TAG, "Ignoring message " + msg.what);
+ return;
+ }
+ }
+ }
+}