summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt731
-rw-r--r--core/java/android/alsa/AlsaCardsParser.java2
-rw-r--r--core/java/android/alsa/AlsaDevicesParser.java2
-rw-r--r--core/java/android/alsa/LineTokenizer.java2
-rw-r--r--core/java/android/app/Activity.java81
-rw-r--r--core/java/android/app/ActivityOptions.java269
-rw-r--r--core/java/android/app/ActivityTransitionCoordinator.java824
-rw-r--r--core/java/android/app/ActivityTransitionState.java204
-rw-r--r--core/java/android/app/EnterTransitionCoordinator.java542
-rw-r--r--core/java/android/app/ExitTransitionCoordinator.java308
-rw-r--r--core/java/android/app/FragmentBreadCrumbs.java6
-rw-r--r--core/java/android/app/SharedElementListener.java87
-rw-r--r--core/java/android/bluetooth/IBluetoothGatt.aidl2
-rw-r--r--core/java/android/content/res/Resources.java14
-rw-r--r--core/java/android/content/res/TypedArray.java34
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java186
-rw-r--r--core/java/android/hardware/camera2/CameraDevice.java23
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java14
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java22
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java51
-rw-r--r--core/java/android/hardware/camera2/ICameraDeviceUser.aidl2
-rw-r--r--core/java/android/hardware/camera2/StreamConfigurationMap.java508
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDevice.java2
-rw-r--r--core/java/android/hardware/camera2/impl/CameraMetadataNative.java108
-rw-r--r--core/java/android/hardware/camera2/marshal/impl/MarshalQueryableReprocessFormatsMap.java8
-rw-r--r--core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfiguration.java2
-rw-r--r--core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfigurationDuration.java2
-rw-r--r--core/java/android/hardware/camera2/params/ReprocessFormatsMap.java (renamed from core/java/android/hardware/camera2/ReprocessFormatsMap.java)24
-rw-r--r--core/java/android/hardware/camera2/params/StreamConfiguration.java (renamed from core/java/android/hardware/camera2/StreamConfiguration.java)10
-rw-r--r--core/java/android/hardware/camera2/params/StreamConfigurationDuration.java (renamed from core/java/android/hardware/camera2/StreamConfigurationDuration.java)9
-rw-r--r--core/java/android/hardware/camera2/params/StreamConfigurationMap.java949
-rw-r--r--core/java/android/hardware/camera2/utils/LongParcelable.aidl (renamed from core/java/android/hardware/camera2/LongParcelable.aidl)4
-rw-r--r--core/java/android/hardware/camera2/utils/LongParcelable.java (renamed from core/java/android/hardware/camera2/LongParcelable.java)2
-rw-r--r--core/java/android/hardware/hdmi/HdmiCec.java8
-rw-r--r--core/java/android/net/LinkProperties.java1
-rw-r--r--core/java/android/os/BatteryManager.java4
-rw-r--r--core/java/android/os/BatteryProperty.java30
-rw-r--r--core/java/android/os/BatteryStats.java110
-rw-r--r--core/java/android/os/PowerManagerInternal.java8
-rw-r--r--core/java/android/preference/VolumePreference.java2
-rw-r--r--core/java/android/provider/Settings.java11
-rw-r--r--core/java/android/transition/Transition.java128
-rw-r--r--core/java/android/transition/TransitionInflater.java37
-rw-r--r--core/java/android/view/RenderNode.java5
-rw-r--r--core/java/android/view/RenderNodeAnimator.java24
-rw-r--r--core/java/android/view/View.java27
-rw-r--r--core/java/android/view/ViewGroup.java4
-rw-r--r--core/java/android/view/Window.java87
-rw-r--r--core/java/android/view/WindowManager.java13
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java639
-rw-r--r--core/java/android/webkit/BrowserDownloadListener.java57
-rw-r--r--core/java/android/webkit/WebBackForwardListClient.java40
-rw-r--r--core/java/android/widget/RtlSpacingHelper.java91
-rw-r--r--core/java/android/widget/Toolbar.java160
-rw-r--r--core/java/android/widget/VideoView.java2
-rw-r--r--core/java/com/android/internal/app/IBatteryStats.aidl9
-rw-r--r--core/java/com/android/internal/app/WindowDecorActionBar.java2
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java125
-rw-r--r--core/java/com/android/internal/widget/multiwaveview/GlowPadView.java8
-rw-r--r--core/jni/Android.mk6
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android/graphics/Matrix.cpp8
-rw-r--r--core/jni/android/graphics/pdf/PdfRenderer.cpp279
-rw-r--r--core/jni/android_util_Binder.cpp32
-rw-r--r--core/jni/android_view_GLES20Canvas.cpp4
-rw-r--r--core/jni/android_view_RenderNode.cpp39
-rw-r--r--core/jni/android_view_RenderNodeAnimator.cpp38
-rw-r--r--core/jni/android_view_ThreadedRenderer.cpp6
-rw-r--r--core/res/res/values-watch/config.xml3
-rw-r--r--core/res/res/values/attrs.xml48
-rw-r--r--core/res/res/values/public.xml15
-rw-r--r--core/res/res/values/styles_device_defaults.xml6
-rw-r--r--core/res/res/values/styles_quantum.xml2
-rw-r--r--core/res/res/values/themes.xml3
-rw-r--r--core/res/res/values/themes_quantum.xml8
-rw-r--r--core/tests/coretests/src/android/view/VelocityTest.java6
-rw-r--r--graphics/java/android/graphics/ImageFormat.java1
-rw-r--r--graphics/java/android/graphics/LayerRasterizer.java3
-rw-r--r--graphics/java/android/graphics/Matrix.java11
-rw-r--r--graphics/java/android/graphics/Outline.java50
-rw-r--r--graphics/java/android/graphics/Paint.java10
-rw-r--r--graphics/java/android/graphics/Rasterizer.java1
-rw-r--r--graphics/java/android/graphics/drawable/BitmapDrawable.java348
-rw-r--r--graphics/java/android/graphics/drawable/ColorDrawable.java2
-rw-r--r--graphics/java/android/graphics/drawable/GradientDrawable.java14
-rw-r--r--graphics/java/android/graphics/drawable/LayerDrawable.java2
-rw-r--r--graphics/java/android/graphics/drawable/NinePatchDrawable.java225
-rw-r--r--graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java2
-rw-r--r--graphics/java/android/graphics/drawable/VectorDrawable.java2
-rw-r--r--graphics/java/android/graphics/pdf/PdfDocument.java4
-rw-r--r--graphics/java/android/graphics/pdf/PdfRenderer.java391
-rw-r--r--libs/hwui/Animator.cpp145
-rw-r--r--libs/hwui/Animator.h102
-rw-r--r--libs/hwui/DeferredDisplayList.cpp11
-rw-r--r--libs/hwui/DeferredDisplayList.h1
-rw-r--r--libs/hwui/OpenGLRenderer.cpp47
-rw-r--r--libs/hwui/OpenGLRenderer.h2
-rw-r--r--libs/hwui/Outline.h13
-rw-r--r--libs/hwui/Program.h28
-rw-r--r--libs/hwui/ProgramCache.cpp50
-rw-r--r--libs/hwui/Rect.h2
-rw-r--r--libs/hwui/RenderNode.cpp38
-rw-r--r--libs/hwui/RenderNode.h28
-rw-r--r--libs/hwui/Snapshot.cpp50
-rw-r--r--libs/hwui/Snapshot.h42
-rw-r--r--libs/hwui/StatefulBaseRenderer.cpp20
-rw-r--r--libs/hwui/StatefulBaseRenderer.h10
-rw-r--r--libs/hwui/TreeInfo.h4
-rw-r--r--libs/hwui/utils/MathUtils.h4
-rw-r--r--media/java/android/media/TtmlRenderer.java751
-rw-r--r--media/java/android/media/session/ISession.aidl1
-rw-r--r--media/java/android/media/session/ISessionCallback.aidl1
-rw-r--r--media/java/android/media/session/Session.java71
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java375
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_qs_location_off.pngbin1729 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_qs_location_on.pngbin1354 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_qs_location_off.pngbin1158 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_qs_location_on.pngbin937 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_qs_location_off.pngbin2443 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_qs_location_on.pngbin1768 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_off.pngbin3202 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_on.pngbin2441 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable/ic_location_24_01.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_location_24_02.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_location_24_03.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_location_24_04.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_location_24_05.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_location_24_06.xml33
-rw-r--r--packages/SystemUI/res/drawable/ic_location_24_07.xml30
-rw-r--r--packages/SystemUI/res/drawable/ic_location_24_08.xml30
-rw-r--r--packages/SystemUI/res/drawable/ic_location_24_09.xml30
-rw-r--r--packages/SystemUI/res/drawable/ic_location_24_10.xml30
-rw-r--r--packages/SystemUI/res/drawable/ic_location_24_11.xml30
-rw-r--r--packages/SystemUI/res/drawable/ic_location_off_anim.xml31
-rw-r--r--packages/SystemUI/res/drawable/ic_location_on_anim.xml31
-rw-r--r--packages/SystemUI/res/values/colors.xml1
-rw-r--r--packages/SystemUI/res/values/styles.xml5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java3
-rw-r--r--policy/src/com/android/internal/policy/impl/BarController.java12
-rw-r--r--policy/src/com/android/internal/policy/impl/GlobalActions.java19
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindow.java132
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindowManager.java27
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java26
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java70
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java6
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java6
-rw-r--r--services/core/java/com/android/server/hdmi/NewDeviceAction.java2
-rw-r--r--services/core/java/com/android/server/media/MediaRouteProviderProxy.java29
-rw-r--r--services/core/java/com/android/server/media/MediaRouteProviderWatcher.java12
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java106
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java365
-rw-r--r--services/core/java/com/android/server/media/MediaSessionStack.java12
-rw-r--r--services/core/java/com/android/server/notification/ValidateNotificationPeople.java112
-rw-r--r--services/core/java/com/android/server/power/Notifier.java13
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java40
-rw-r--r--services/core/java/com/android/server/wm/ViewServer.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java32
-rw-r--r--services/core/jni/com_android_server_hdmi_HdmiCecService.cpp8
-rw-r--r--services/usb/java/com/android/server/usb/UsbHostManager.java4
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml9
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java11
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/ClipOutlineActivity.java87
-rw-r--r--tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java9
-rw-r--r--tools/aapt/Command.cpp47
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java11
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java10
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java15
-rw-r--r--tools/layoutlib/bridge/src/android/os/SystemProperties_Delegate.java (renamed from tools/layoutlib/bridge/src/android/os/Build_Delegate.java)23
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java2
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java34
175 files changed, 8172 insertions, 3589 deletions
diff --git a/api/current.txt b/api/current.txt
index 97e23fb..d3996e4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -250,7 +250,7 @@ package android {
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 = 16843829; // 0x1010435
+ field public static final int actionBarTheme = 16843828; // 0x1010434
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 @@ package android {
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 = 16843849; // 0x1010449
+ field public static final int actionOverflowMenuStyle = 16843848; // 0x1010448
field public static final int actionProviderClass = 16843657; // 0x1010389
field public static final int actionViewClass = 16843516; // 0x10102fc
field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
@@ -313,7 +313,7 @@ package android {
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 = 16843851; // 0x101044b
+ field public static final int autoRemoveFromRecents = 16843850; // 0x101044a
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,27 +382,27 @@ package android {
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 = 16843818; // 0x101042a
+ field public static final int clipToPath = 16843817; // 0x1010429
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 = 16843834; // 0x101043a
+ field public static final int colorAccent = 16843833; // 0x1010439
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 = 16843823; // 0x101042f
- field public static final int colorButtonPressed = 16843824; // 0x1010430
- field public static final int colorControlActivated = 16843822; // 0x101042e
- field public static final int colorControlNormal = 16843821; // 0x101042d
+ field public static final int colorButtonNormal = 16843822; // 0x101042e
+ field public static final int colorButtonPressed = 16843823; // 0x101042f
+ field public static final int colorControlActivated = 16843821; // 0x101042d
+ field public static final int colorControlNormal = 16843820; // 0x101042c
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 = 16843832; // 0x1010438
- field public static final int colorPrimaryDark = 16843833; // 0x1010439
- field public static final int colorPrimaryLight = 16843831; // 0x1010437
+ field public static final int colorPrimary = 16843831; // 0x1010437
+ field public static final int colorPrimaryDark = 16843832; // 0x1010438
+ field public static final int colorPrimaryLight = 16843830; // 0x1010436
field public static final int columnCount = 16843639; // 0x1010377
field public static final int columnDelay = 16843215; // 0x10101cf
field public static final int columnOrderPreserved = 16843640; // 0x1010378
@@ -417,10 +417,14 @@ package android {
field public static final int content = 16843355; // 0x101025b
field public static final int contentAuthority = 16843408; // 0x1010290
field public static final int contentDescription = 16843379; // 0x1010273
- field public static final int controlX1 = 16843799; // 0x1010417
- field public static final int controlX2 = 16843801; // 0x1010419
- field public static final int controlY1 = 16843800; // 0x1010418
- field public static final int controlY2 = 16843802; // 0x101041a
+ field public static final int contentInsetEnd = 16843863; // 0x1010457
+ field public static final int contentInsetLeft = 16843864; // 0x1010458
+ field public static final int contentInsetRight = 16843865; // 0x1010459
+ field public static final int contentInsetStart = 16843862; // 0x1010456
+ field public static final int controlX1 = 16843798; // 0x1010416
+ field public static final int controlX2 = 16843800; // 0x1010418
+ field public static final int controlY1 = 16843799; // 0x1010417
+ field public static final int controlY2 = 16843801; // 0x1010419
field public static final int cropToPadding = 16843043; // 0x1010123
field public static final int cursorVisible = 16843090; // 0x1010152
field public static final int customNavigationLayout = 16843474; // 0x10102d2
@@ -461,7 +465,7 @@ package android {
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 = 16843850; // 0x101044a
+ field public static final int documentLaunchMode = 16843849; // 0x1010449
field public static final int drawSelectorOnTop = 16843004; // 0x10100fc
field public static final int drawable = 16843161; // 0x1010199
field public static final int drawableBottom = 16843118; // 0x101016e
@@ -490,7 +494,7 @@ package android {
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 = 16843845; // 0x1010445
+ field public static final int elevation = 16843844; // 0x1010444
field public static final int ellipsize = 16842923; // 0x10100ab
field public static final int ems = 16843096; // 0x1010158
field public static final int enabled = 16842766; // 0x101000e
@@ -500,10 +504,10 @@ package android {
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 = 16843847; // 0x1010447
+ field public static final int excludeClass = 16843846; // 0x1010446
field public static final int excludeFromRecents = 16842775; // 0x1010017
- field public static final int excludeId = 16843846; // 0x1010446
- field public static final int excludeViewName = 16843858; // 0x1010452
+ field public static final int excludeId = 16843845; // 0x1010445
+ field public static final int excludeViewName = 16843857; // 0x1010451
field public static final int exitFadeDuration = 16843533; // 0x101030d
field public static final int expandableListPreferredChildIndicatorLeft = 16842834; // 0x1010052
field public static final int expandableListPreferredChildIndicatorRight = 16842835; // 0x1010053
@@ -528,15 +532,15 @@ package android {
field public static final int fastScrollOverlayPosition = 16843578; // 0x101033a
field public static final int fastScrollPreviewBackgroundLeft = 16843575; // 0x1010337
field public static final int fastScrollPreviewBackgroundRight = 16843576; // 0x1010338
- field public static final int fastScrollStyle = 16843794; // 0x1010412
+ field public static final int fastScrollStyle = 16843793; // 0x1010411
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 = 16843808; // 0x1010420
+ field public static final int fill = 16843807; // 0x101041f
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 = 16843807; // 0x101041f
+ field public static final int fillOpacity = 16843806; // 0x101041e
field public static final int fillViewport = 16843130; // 0x101017a
field public static final int filter = 16843035; // 0x101011b
field public static final int filterTouchesWhenObscured = 16843460; // 0x10102c4
@@ -556,7 +560,6 @@ package android {
field public static final int format12Hour = 16843722; // 0x10103ca
field public static final int format24Hour = 16843723; // 0x10103cb
field public static final int fragment = 16843491; // 0x10102e3
- field public static final int fragmentBreadCrumbsStyle = 16843793; // 0x1010411
field public static final int fragmentCloseEnterAnimation = 16843495; // 0x10102e7
field public static final int fragmentCloseExitAnimation = 16843496; // 0x10102e8
field public static final int fragmentFadeEnterAnimation = 16843497; // 0x10102e9
@@ -566,7 +569,7 @@ package android {
field public static final int freezesText = 16843116; // 0x101016c
field public static final int fromAlpha = 16843210; // 0x10101ca
field public static final int fromDegrees = 16843187; // 0x10101b3
- field public static final int fromId = 16843854; // 0x101044e
+ field public static final int fromId = 16843853; // 0x101044d
field public static final int fromScene = 16843741; // 0x10103dd
field public static final int fromXDelta = 16843206; // 0x10101c6
field public static final int fromXScale = 16843202; // 0x10101c2
@@ -599,7 +602,7 @@ package android {
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 = 16843848; // 0x1010448
+ field public static final int hideOnContentScroll = 16843847; // 0x1010447
field public static final int hint = 16843088; // 0x1010150
field public static final int homeAsUpIndicator = 16843531; // 0x101030b
field public static final int homeLayout = 16843549; // 0x101031d
@@ -796,6 +799,7 @@ package android {
field public static final int manageSpaceActivity = 16842756; // 0x1010004
field public static final int mapViewStyle = 16842890; // 0x101008a
field public static final int marqueeRepeatLimit = 16843293; // 0x101021d
+ field public static final int matchOrder = 16843858; // 0x1010452
field public static final int max = 16843062; // 0x1010136
field public static final int maxDate = 16843584; // 0x1010340
field public static final int maxEms = 16843095; // 0x1010157
@@ -828,9 +832,10 @@ package android {
field public static final int moreIcon = 16843061; // 0x1010135
field public static final int multiprocess = 16842771; // 0x1010013
field public static final int name = 16842755; // 0x1010003
+ field public static final int navigationBarColor = 16843861; // 0x1010455
field public static final int navigationMode = 16843471; // 0x10102cf
field public static final int negativeButtonText = 16843254; // 0x10101f6
- field public static final int nestedScrollingEnabled = 16843835; // 0x101043b
+ field public static final int nestedScrollingEnabled = 16843834; // 0x101043a
field public static final int nextFocusDown = 16842980; // 0x10100e4
field public static final int nextFocusForward = 16843580; // 0x101033c
field public static final int nextFocusLeft = 16842977; // 0x10100e1
@@ -872,18 +877,18 @@ package android {
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 = 16843809; // 0x1010421
+ field public static final int pathData = 16843808; // 0x1010420
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 = 16843825; // 0x1010431
+ field public static final int persistable = 16843824; // 0x1010430
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 = 16843820; // 0x101042c
+ field public static final int pinned = 16843819; // 0x101042b
field public static final int pivotX = 16843189; // 0x10101b5
field public static final int pivotY = 16843190; // 0x10101b6
field public static final int popupAnimationStyle = 16843465; // 0x10102c9
@@ -947,7 +952,7 @@ package android {
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 = 16843819; // 0x101042b
+ field public static final int requiredForProfile = 16843818; // 0x101042a
field public static final int requiresFadingEdge = 16843685; // 0x10103a5
field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
field public static final int resizeMode = 16843619; // 0x1010363
@@ -956,7 +961,7 @@ package android {
field public static final int restoreAnyVersion = 16843450; // 0x10102ba
field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
field public static final int restrictedAccountType = 16843733; // 0x10103d5
- field public static final int reversible = 16843855; // 0x101044f
+ field public static final int reversible = 16843854; // 0x101044e
field public static final int right = 16843183; // 0x10101af
field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
field public static final int ringtoneType = 16843257; // 0x10101f9
@@ -1012,7 +1017,7 @@ package android {
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 sessionService = 16843842; // 0x1010442
+ field public static final int sessionService = 16843841; // 0x1010441
field public static final int settingsActivity = 16843301; // 0x1010225
field public static final int shadowColor = 16843105; // 0x1010161
field public static final int shadowDx = 16843106; // 0x1010162
@@ -1033,7 +1038,7 @@ package android {
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 = 16843828; // 0x1010434
+ field public static final int slideEdge = 16843827; // 0x1010433
field public static final int smallIcon = 16843422; // 0x101029e
field public static final int smallScreens = 16843396; // 0x1010284
field public static final int smoothScrollbar = 16843313; // 0x1010231
@@ -1045,19 +1050,19 @@ package android {
field public static final int spinnerStyle = 16842881; // 0x1010081
field public static final int spinnersShown = 16843595; // 0x101034b
field public static final int splitMotionEvents = 16843503; // 0x10102ef
- field public static final int splitTrack = 16843856; // 0x1010450
+ field public static final int splitTrack = 16843855; // 0x101044f
field public static final int src = 16843033; // 0x1010119
field public static final int ssp = 16843747; // 0x10103e3
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 = 16843843; // 0x1010443
+ field public static final int stackViewStyle = 16843842; // 0x1010442
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 = 16843852; // 0x101044c
+ field public static final int stateListAnimator = 16843851; // 0x101044b
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
@@ -1082,18 +1087,19 @@ package android {
field public static final int state_single = 16842915; // 0x10100a3
field public static final int state_window_focused = 16842909; // 0x101009d
field public static final int staticWallpaperPreview = 16843569; // 0x1010331
+ field public static final int statusBarColor = 16843860; // 0x1010454
field public static final int stepSize = 16843078; // 0x1010146
field public static final int stopWithTask = 16843626; // 0x101036a
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 = 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 stroke = 16843809; // 0x1010421
+ field public static final int strokeLineCap = 16843815; // 0x1010427
+ field public static final int strokeLineJoin = 16843816; // 0x1010428
+ field public static final int strokeOpacity = 16843810; // 0x1010422
+ field public static final int strokeWidth = 16843811; // 0x1010423
field public static final int subtitle = 16843473; // 0x10102d1
- field public static final int subtitleTextAppearance = 16843827; // 0x1010433
+ field public static final int subtitleTextAppearance = 16843826; // 0x1010432
field public static final int subtitleTextStyle = 16843513; // 0x10102f9
field public static final int subtypeExtraValue = 16843674; // 0x101039a
field public static final int subtypeId = 16843713; // 0x10103c1
@@ -1110,7 +1116,7 @@ package android {
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 = 16843844; // 0x1010444
+ field public static final int switchStyle = 16843843; // 0x1010443
field public static final int switchTextAppearance = 16843630; // 0x101036e
field public static final int switchTextOff = 16843628; // 0x101036c
field public static final int switchTextOn = 16843627; // 0x101036b
@@ -1126,7 +1132,7 @@ package android {
field public static final int targetId = 16843740; // 0x10103dc
field public static final int targetPackage = 16842785; // 0x1010021
field public static final int targetSdkVersion = 16843376; // 0x1010270
- field public static final int targetViewName = 16843857; // 0x1010451
+ field public static final int targetViewName = 16843856; // 0x1010450
field public static final int taskAffinity = 16842770; // 0x1010012
field public static final int taskCloseEnterAnimation = 16842942; // 0x10100be
field public static final int taskCloseExitAnimation = 16842943; // 0x10100bf
@@ -1148,7 +1154,7 @@ package android {
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 = 16843830; // 0x1010436
+ field public static final int textAppearanceListItemSecondary = 16843829; // 0x1010435
field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
field public static final int textAppearanceMedium = 16842817; // 0x1010041
field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
@@ -1209,14 +1215,14 @@ package android {
field public static final int tileMode = 16843265; // 0x1010201
field public static final int timeZone = 16843724; // 0x10103cc
field public static final int tint = 16843041; // 0x1010121
- field public static final int tintMode = 16843798; // 0x1010416
+ field public static final int tintMode = 16843797; // 0x1010415
field public static final int title = 16843233; // 0x10101e1
field public static final int titleCondensed = 16843234; // 0x10101e2
- field public static final int titleTextAppearance = 16843826; // 0x1010432
+ field public static final int titleTextAppearance = 16843825; // 0x1010431
field public static final int titleTextStyle = 16843512; // 0x10102f8
field public static final int toAlpha = 16843211; // 0x10101cb
field public static final int toDegrees = 16843188; // 0x10101b4
- field public static final int toId = 16843853; // 0x101044d
+ field public static final int toId = 16843852; // 0x101044c
field public static final int toScene = 16843742; // 0x10103de
field public static final int toXDelta = 16843207; // 0x10101c7
field public static final int toXScale = 16843203; // 0x10101c3
@@ -1233,14 +1239,14 @@ package android {
field public static final int transformPivotX = 16843552; // 0x1010320
field public static final int transformPivotY = 16843553; // 0x1010321
field public static final int transition = 16843743; // 0x10103df
- field public static final int transitionGroup = 16843804; // 0x101041c
+ field public static final int transitionGroup = 16843803; // 0x101041b
field public static final int transitionOrdering = 16843744; // 0x10103e0
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 trimPathEnd = 16843814; // 0x1010426
- field public static final int trimPathOffset = 16843815; // 0x1010427
- field public static final int trimPathStart = 16843813; // 0x1010425
+ field public static final int translationZ = 16843796; // 0x1010414
+ field public static final int trimPathEnd = 16843813; // 0x1010425
+ field public static final int trimPathOffset = 16843814; // 0x1010426
+ field public static final int trimPathStart = 16843812; // 0x1010424
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,9 +1271,9 @@ package android {
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 viewName = 16843803; // 0x101041b
- field public static final int viewportHeight = 16843806; // 0x101041e
- field public static final int viewportWidth = 16843805; // 0x101041d
+ field public static final int viewName = 16843802; // 0x101041a
+ field public static final int viewportHeight = 16843805; // 0x101041d
+ field public static final int viewportWidth = 16843804; // 0x101041c
field public static final int visibility = 16842972; // 0x10100dc
field public static final int visible = 16843156; // 0x1010194
field public static final int vmSafeMode = 16843448; // 0x10102b8
@@ -1296,20 +1302,21 @@ package android {
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 = 16843841; // 0x1010441
- field public static final int windowAllowExitTransitionOverlap = 16843840; // 0x1010440
+ field public static final int windowAllowEnterTransitionOverlap = 16843840; // 0x1010440
+ field public static final int windowAllowExitTransitionOverlap = 16843839; // 0x101043f
field public static final int windowAnimationStyle = 16842926; // 0x10100ae
field public static final int windowBackground = 16842836; // 0x1010054
field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
field public static final int windowContentOverlay = 16842841; // 0x1010059
- field public static final int windowContentTransitionManager = 16843796; // 0x1010414
- field public static final int windowContentTransitions = 16843795; // 0x1010413
+ field public static final int windowContentTransitionManager = 16843795; // 0x1010413
+ field public static final int windowContentTransitions = 16843794; // 0x1010412
field public static final int windowDisablePreview = 16843298; // 0x1010222
+ field public static final int windowDrawsSystemBarBackgrounds = 16843859; // 0x1010453
field public static final int windowEnableSplitTouch = 16843543; // 0x1010317
field public static final int windowEnterAnimation = 16842932; // 0x10100b4
- field public static final int windowEnterTransition = 16843836; // 0x101043c
+ field public static final int windowEnterTransition = 16843835; // 0x101043b
field public static final int windowExitAnimation = 16842933; // 0x10100b5
- field public static final int windowExitTransition = 16843837; // 0x101043d
+ field public static final int windowExitTransition = 16843836; // 0x101043c
field public static final int windowFrame = 16842837; // 0x1010055
field public static final int windowFullscreen = 16843277; // 0x101020d
field public static final int windowHideAnimation = 16842935; // 0x10100b7
@@ -1320,8 +1327,8 @@ package android {
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 = 16843838; // 0x101043e
- field public static final int windowSharedElementExitTransition = 16843839; // 0x101043f
+ field public static final int windowSharedElementEnterTransition = 16843837; // 0x101043d
+ field public static final int windowSharedElementExitTransition = 16843838; // 0x101043e
field public static final int windowShowAnimation = 16842934; // 0x10100b6
field public static final int windowShowWallpaper = 16843410; // 0x1010292
field public static final int windowSoftInputMode = 16843307; // 0x101022b
@@ -1858,52 +1865,52 @@ package android {
field public static final int TextAppearance_Large_Inverse = 16973891; // 0x1030043
field public static final int TextAppearance_Medium = 16973892; // 0x1030044
field public static final int TextAppearance_Medium_Inverse = 16973893; // 0x1030045
- field public static final int TextAppearance_Quantum = 16974352; // 0x1030210
- field public static final int TextAppearance_Quantum_Body1 = 16974549; // 0x10302d5
- field public static final int TextAppearance_Quantum_Body2 = 16974548; // 0x10302d4
- field public static final int TextAppearance_Quantum_Button = 16974552; // 0x10302d8
- field public static final int TextAppearance_Quantum_Caption = 16974550; // 0x10302d6
- field public static final int TextAppearance_Quantum_DialogWindowTitle = 16974353; // 0x1030211
- field public static final int TextAppearance_Quantum_Display1 = 16974544; // 0x10302d0
- field public static final int TextAppearance_Quantum_Display2 = 16974543; // 0x10302cf
- field public static final int TextAppearance_Quantum_Display3 = 16974542; // 0x10302ce
- field public static final int TextAppearance_Quantum_Display4 = 16974541; // 0x10302cd
- field public static final int TextAppearance_Quantum_Headline = 16974545; // 0x10302d1
- field public static final int TextAppearance_Quantum_Inverse = 16974354; // 0x1030212
- field public static final int TextAppearance_Quantum_Large = 16974355; // 0x1030213
- field public static final int TextAppearance_Quantum_Large_Inverse = 16974356; // 0x1030214
- field public static final int TextAppearance_Quantum_Medium = 16974357; // 0x1030215
- field public static final int TextAppearance_Quantum_Medium_Inverse = 16974358; // 0x1030216
- field public static final int TextAppearance_Quantum_Menu = 16974551; // 0x10302d7
- field public static final int TextAppearance_Quantum_SearchResult_Subtitle = 16974359; // 0x1030217
- field public static final int TextAppearance_Quantum_SearchResult_Title = 16974360; // 0x1030218
- field public static final int TextAppearance_Quantum_Small = 16974361; // 0x1030219
- field public static final int TextAppearance_Quantum_Small_Inverse = 16974362; // 0x103021a
- field public static final int TextAppearance_Quantum_Subhead = 16974547; // 0x10302d3
- field public static final int TextAppearance_Quantum_Title = 16974546; // 0x10302d2
- field public static final int TextAppearance_Quantum_Widget = 16974364; // 0x103021c
- field public static final int TextAppearance_Quantum_Widget_ActionBar_Menu = 16974365; // 0x103021d
- field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle = 16974366; // 0x103021e
- field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle_Inverse = 16974367; // 0x103021f
- field public static final int TextAppearance_Quantum_Widget_ActionBar_Title = 16974368; // 0x1030220
- field public static final int TextAppearance_Quantum_Widget_ActionBar_Title_Inverse = 16974369; // 0x1030221
- field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle = 16974370; // 0x1030222
- field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle_Inverse = 16974371; // 0x1030223
- field public static final int TextAppearance_Quantum_Widget_ActionMode_Title = 16974372; // 0x1030224
- field public static final int TextAppearance_Quantum_Widget_ActionMode_Title_Inverse = 16974373; // 0x1030225
- field public static final int TextAppearance_Quantum_Widget_Button = 16974374; // 0x1030226
- field public static final int TextAppearance_Quantum_Widget_DropDownHint = 16974375; // 0x1030227
- field public static final int TextAppearance_Quantum_Widget_DropDownItem = 16974376; // 0x1030228
- field public static final int TextAppearance_Quantum_Widget_EditText = 16974377; // 0x1030229
- field public static final int TextAppearance_Quantum_Widget_IconMenu_Item = 16974378; // 0x103022a
- field public static final int TextAppearance_Quantum_Widget_PopupMenu = 16974379; // 0x103022b
- field public static final int TextAppearance_Quantum_Widget_PopupMenu_Large = 16974380; // 0x103022c
- field public static final int TextAppearance_Quantum_Widget_PopupMenu_Small = 16974381; // 0x103022d
- field public static final int TextAppearance_Quantum_Widget_TabWidget = 16974382; // 0x103022e
- field public static final int TextAppearance_Quantum_Widget_TextView = 16974383; // 0x103022f
- field public static final int TextAppearance_Quantum_Widget_TextView_PopupMenu = 16974384; // 0x1030230
- field public static final int TextAppearance_Quantum_Widget_TextView_SpinnerItem = 16974385; // 0x1030231
- field public static final int TextAppearance_Quantum_WindowTitle = 16974363; // 0x103021b
+ field public static final int TextAppearance_Quantum = 16974348; // 0x103020c
+ field public static final int TextAppearance_Quantum_Body1 = 16974543; // 0x10302cf
+ field public static final int TextAppearance_Quantum_Body2 = 16974542; // 0x10302ce
+ field public static final int TextAppearance_Quantum_Button = 16974546; // 0x10302d2
+ field public static final int TextAppearance_Quantum_Caption = 16974544; // 0x10302d0
+ field public static final int TextAppearance_Quantum_DialogWindowTitle = 16974349; // 0x103020d
+ field public static final int TextAppearance_Quantum_Display1 = 16974538; // 0x10302ca
+ field public static final int TextAppearance_Quantum_Display2 = 16974537; // 0x10302c9
+ field public static final int TextAppearance_Quantum_Display3 = 16974536; // 0x10302c8
+ field public static final int TextAppearance_Quantum_Display4 = 16974535; // 0x10302c7
+ field public static final int TextAppearance_Quantum_Headline = 16974539; // 0x10302cb
+ field public static final int TextAppearance_Quantum_Inverse = 16974350; // 0x103020e
+ field public static final int TextAppearance_Quantum_Large = 16974351; // 0x103020f
+ field public static final int TextAppearance_Quantum_Large_Inverse = 16974352; // 0x1030210
+ field public static final int TextAppearance_Quantum_Medium = 16974353; // 0x1030211
+ field public static final int TextAppearance_Quantum_Medium_Inverse = 16974354; // 0x1030212
+ field public static final int TextAppearance_Quantum_Menu = 16974545; // 0x10302d1
+ field public static final int TextAppearance_Quantum_SearchResult_Subtitle = 16974355; // 0x1030213
+ field public static final int TextAppearance_Quantum_SearchResult_Title = 16974356; // 0x1030214
+ field public static final int TextAppearance_Quantum_Small = 16974357; // 0x1030215
+ field public static final int TextAppearance_Quantum_Small_Inverse = 16974358; // 0x1030216
+ field public static final int TextAppearance_Quantum_Subhead = 16974541; // 0x10302cd
+ field public static final int TextAppearance_Quantum_Title = 16974540; // 0x10302cc
+ field public static final int TextAppearance_Quantum_Widget = 16974360; // 0x1030218
+ field public static final int TextAppearance_Quantum_Widget_ActionBar_Menu = 16974361; // 0x1030219
+ field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle = 16974362; // 0x103021a
+ field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle_Inverse = 16974363; // 0x103021b
+ field public static final int TextAppearance_Quantum_Widget_ActionBar_Title = 16974364; // 0x103021c
+ field public static final int TextAppearance_Quantum_Widget_ActionBar_Title_Inverse = 16974365; // 0x103021d
+ field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle = 16974366; // 0x103021e
+ field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle_Inverse = 16974367; // 0x103021f
+ field public static final int TextAppearance_Quantum_Widget_ActionMode_Title = 16974368; // 0x1030220
+ field public static final int TextAppearance_Quantum_Widget_ActionMode_Title_Inverse = 16974369; // 0x1030221
+ field public static final int TextAppearance_Quantum_Widget_Button = 16974370; // 0x1030222
+ field public static final int TextAppearance_Quantum_Widget_DropDownHint = 16974371; // 0x1030223
+ field public static final int TextAppearance_Quantum_Widget_DropDownItem = 16974372; // 0x1030224
+ field public static final int TextAppearance_Quantum_Widget_EditText = 16974373; // 0x1030225
+ field public static final int TextAppearance_Quantum_Widget_IconMenu_Item = 16974374; // 0x1030226
+ field public static final int TextAppearance_Quantum_Widget_PopupMenu = 16974375; // 0x1030227
+ field public static final int TextAppearance_Quantum_Widget_PopupMenu_Large = 16974376; // 0x1030228
+ field public static final int TextAppearance_Quantum_Widget_PopupMenu_Small = 16974377; // 0x1030229
+ field public static final int TextAppearance_Quantum_Widget_TabWidget = 16974378; // 0x103022a
+ field public static final int TextAppearance_Quantum_Widget_TextView = 16974379; // 0x103022b
+ field public static final int TextAppearance_Quantum_Widget_TextView_PopupMenu = 16974380; // 0x103022c
+ field public static final int TextAppearance_Quantum_Widget_TextView_SpinnerItem = 16974381; // 0x103022d
+ field public static final int TextAppearance_Quantum_WindowTitle = 16974359; // 0x1030217
field public static final int TextAppearance_Small = 16973894; // 0x1030046
field public static final int TextAppearance_Small_Inverse = 16973895; // 0x1030047
field public static final int TextAppearance_StatusBar_EventContent = 16973927; // 0x1030067
@@ -1927,11 +1934,11 @@ package android {
field public static final int TextAppearance_Widget_TextView_SpinnerItem = 16973906; // 0x1030052
field public static final int TextAppearance_WindowTitle = 16973907; // 0x1030053
field public static final int Theme = 16973829; // 0x1030005
- field public static final int ThemeOverlay = 16974414; // 0x103024e
- field public static final int ThemeOverlay_Quantum = 16974415; // 0x103024f
- field public static final int ThemeOverlay_Quantum_ActionBarWidget = 16974418; // 0x1030252
- field public static final int ThemeOverlay_Quantum_Dark = 16974417; // 0x1030251
- field public static final int ThemeOverlay_Quantum_Light = 16974416; // 0x1030250
+ field public static final int ThemeOverlay = 16974410; // 0x103024a
+ field public static final int ThemeOverlay_Quantum = 16974411; // 0x103024b
+ field public static final int ThemeOverlay_Quantum_ActionBarWidget = 16974414; // 0x103024e
+ field public static final int ThemeOverlay_Quantum_Dark = 16974413; // 0x103024d
+ field public static final int ThemeOverlay_Quantum_Light = 16974412; // 0x103024c
field public static final int Theme_Black = 16973832; // 0x1030008
field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
field public static final int Theme_Black_NoTitleBar_Fullscreen = 16973834; // 0x103000a
@@ -2003,34 +2010,34 @@ package android {
field public static final int Theme_NoTitleBar_Fullscreen = 16973831; // 0x1030007
field public static final int Theme_NoTitleBar_OverlayActionModes = 16973930; // 0x103006a
field public static final int Theme_Panel = 16973913; // 0x1030059
- field public static final int Theme_Quantum = 16974386; // 0x1030232
- field public static final int Theme_Quantum_Dialog = 16974387; // 0x1030233
- field public static final int Theme_Quantum_DialogWhenLarge = 16974391; // 0x1030237
- field public static final int Theme_Quantum_DialogWhenLarge_NoActionBar = 16974392; // 0x1030238
- field public static final int Theme_Quantum_Dialog_MinWidth = 16974388; // 0x1030234
- field public static final int Theme_Quantum_Dialog_NoActionBar = 16974389; // 0x1030235
- field public static final int Theme_Quantum_Dialog_NoActionBar_MinWidth = 16974390; // 0x1030236
- field public static final int Theme_Quantum_InputMethod = 16974393; // 0x1030239
- field public static final int Theme_Quantum_Light = 16974401; // 0x1030241
- field public static final int Theme_Quantum_Light_DarkActionBar = 16974402; // 0x1030242
- field public static final int Theme_Quantum_Light_Dialog = 16974403; // 0x1030243
- field public static final int Theme_Quantum_Light_DialogWhenLarge = 16974407; // 0x1030247
- field public static final int Theme_Quantum_Light_DialogWhenLarge_NoActionBar = 16974408; // 0x1030248
- field public static final int Theme_Quantum_Light_Dialog_MinWidth = 16974404; // 0x1030244
- field public static final int Theme_Quantum_Light_Dialog_NoActionBar = 16974405; // 0x1030245
- field public static final int Theme_Quantum_Light_Dialog_NoActionBar_MinWidth = 16974406; // 0x1030246
- field public static final int Theme_Quantum_Light_NoActionBar = 16974409; // 0x1030249
- field public static final int Theme_Quantum_Light_NoActionBar_Fullscreen = 16974410; // 0x103024a
- field public static final int Theme_Quantum_Light_NoActionBar_Overscan = 16974411; // 0x103024b
- field public static final int Theme_Quantum_Light_NoActionBar_TranslucentDecor = 16974412; // 0x103024c
- field public static final int Theme_Quantum_Light_Panel = 16974413; // 0x103024d
- field public static final int Theme_Quantum_NoActionBar = 16974394; // 0x103023a
- field public static final int Theme_Quantum_NoActionBar_Fullscreen = 16974395; // 0x103023b
- field public static final int Theme_Quantum_NoActionBar_Overscan = 16974396; // 0x103023c
- field public static final int Theme_Quantum_NoActionBar_TranslucentDecor = 16974397; // 0x103023d
- field public static final int Theme_Quantum_Panel = 16974398; // 0x103023e
- field public static final int Theme_Quantum_Wallpaper = 16974399; // 0x103023f
- field public static final int Theme_Quantum_Wallpaper_NoTitleBar = 16974400; // 0x1030240
+ field public static final int Theme_Quantum = 16974382; // 0x103022e
+ field public static final int Theme_Quantum_Dialog = 16974383; // 0x103022f
+ field public static final int Theme_Quantum_DialogWhenLarge = 16974387; // 0x1030233
+ field public static final int Theme_Quantum_DialogWhenLarge_NoActionBar = 16974388; // 0x1030234
+ field public static final int Theme_Quantum_Dialog_MinWidth = 16974384; // 0x1030230
+ field public static final int Theme_Quantum_Dialog_NoActionBar = 16974385; // 0x1030231
+ field public static final int Theme_Quantum_Dialog_NoActionBar_MinWidth = 16974386; // 0x1030232
+ field public static final int Theme_Quantum_InputMethod = 16974389; // 0x1030235
+ field public static final int Theme_Quantum_Light = 16974397; // 0x103023d
+ field public static final int Theme_Quantum_Light_DarkActionBar = 16974398; // 0x103023e
+ field public static final int Theme_Quantum_Light_Dialog = 16974399; // 0x103023f
+ field public static final int Theme_Quantum_Light_DialogWhenLarge = 16974403; // 0x1030243
+ field public static final int Theme_Quantum_Light_DialogWhenLarge_NoActionBar = 16974404; // 0x1030244
+ field public static final int Theme_Quantum_Light_Dialog_MinWidth = 16974400; // 0x1030240
+ field public static final int Theme_Quantum_Light_Dialog_NoActionBar = 16974401; // 0x1030241
+ field public static final int Theme_Quantum_Light_Dialog_NoActionBar_MinWidth = 16974402; // 0x1030242
+ field public static final int Theme_Quantum_Light_NoActionBar = 16974405; // 0x1030245
+ field public static final int Theme_Quantum_Light_NoActionBar_Fullscreen = 16974406; // 0x1030246
+ field public static final int Theme_Quantum_Light_NoActionBar_Overscan = 16974407; // 0x1030247
+ field public static final int Theme_Quantum_Light_NoActionBar_TranslucentDecor = 16974408; // 0x1030248
+ field public static final int Theme_Quantum_Light_Panel = 16974409; // 0x1030249
+ field public static final int Theme_Quantum_NoActionBar = 16974390; // 0x1030236
+ field public static final int Theme_Quantum_NoActionBar_Fullscreen = 16974391; // 0x1030237
+ field public static final int Theme_Quantum_NoActionBar_Overscan = 16974392; // 0x1030238
+ field public static final int Theme_Quantum_NoActionBar_TranslucentDecor = 16974393; // 0x1030239
+ field public static final int Theme_Quantum_Panel = 16974394; // 0x103023a
+ field public static final int Theme_Quantum_Wallpaper = 16974395; // 0x103023b
+ field public static final int Theme_Quantum_Wallpaper_NoTitleBar = 16974396; // 0x103023c
field public static final int Theme_Translucent = 16973839; // 0x103000f
field public static final int Theme_Translucent_NoTitleBar = 16973840; // 0x1030010
field public static final int Theme_Translucent_NoTitleBar_Fullscreen = 16973841; // 0x1030011
@@ -2087,8 +2094,7 @@ package android {
field public static final int Widget_DeviceDefault_DropDownItem_Spinner = 16974178; // 0x1030162
field public static final int Widget_DeviceDefault_EditText = 16974154; // 0x103014a
field public static final int Widget_DeviceDefault_ExpandableListView = 16974155; // 0x103014b
- field public static final int Widget_DeviceDefault_FastScroll = 16974346; // 0x103020a
- field public static final int Widget_DeviceDefault_FragmentBreadCrumbs = 16974347; // 0x103020b
+ field public static final int Widget_DeviceDefault_FastScroll = 16974344; // 0x1030208
field public static final int Widget_DeviceDefault_GridView = 16974156; // 0x103014c
field public static final int Widget_DeviceDefault_HorizontalScrollView = 16974171; // 0x103015b
field public static final int Widget_DeviceDefault_ImageButton = 16974157; // 0x103014d
@@ -2122,8 +2128,7 @@ package android {
field public static final int Widget_DeviceDefault_Light_DropDownItem_Spinner = 16974233; // 0x1030199
field public static final int Widget_DeviceDefault_Light_EditText = 16974206; // 0x103017e
field public static final int Widget_DeviceDefault_Light_ExpandableListView = 16974207; // 0x103017f
- field public static final int Widget_DeviceDefault_Light_FastScroll = 16974349; // 0x103020d
- field public static final int Widget_DeviceDefault_Light_FragmentBreadCrumbs = 16974350; // 0x103020e
+ field public static final int Widget_DeviceDefault_Light_FastScroll = 16974346; // 0x103020a
field public static final int Widget_DeviceDefault_Light_GridView = 16974208; // 0x1030180
field public static final int Widget_DeviceDefault_Light_HorizontalScrollView = 16974226; // 0x1030192
field public static final int Widget_DeviceDefault_Light_ImageButton = 16974209; // 0x1030181
@@ -2147,7 +2152,7 @@ package android {
field public static final int Widget_DeviceDefault_Light_ScrollView = 16974225; // 0x1030191
field public static final int Widget_DeviceDefault_Light_SeekBar = 16974220; // 0x103018c
field public static final int Widget_DeviceDefault_Light_Spinner = 16974227; // 0x1030193
- field public static final int Widget_DeviceDefault_Light_StackView = 16974351; // 0x103020f
+ field public static final int Widget_DeviceDefault_Light_StackView = 16974347; // 0x103020b
field public static final int Widget_DeviceDefault_Light_Tab = 16974237; // 0x103019d
field public static final int Widget_DeviceDefault_Light_TabWidget = 16974229; // 0x1030195
field public static final int Widget_DeviceDefault_Light_TextView = 16974202; // 0x103017a
@@ -2171,7 +2176,7 @@ package android {
field public static final int Widget_DeviceDefault_ScrollView = 16974170; // 0x103015a
field public static final int Widget_DeviceDefault_SeekBar = 16974165; // 0x1030155
field public static final int Widget_DeviceDefault_Spinner = 16974172; // 0x103015c
- field public static final int Widget_DeviceDefault_StackView = 16974348; // 0x103020c
+ field public static final int Widget_DeviceDefault_StackView = 16974345; // 0x1030209
field public static final int Widget_DeviceDefault_Tab = 16974189; // 0x103016d
field public static final int Widget_DeviceDefault_TabWidget = 16974174; // 0x103015e
field public static final int Widget_DeviceDefault_TextView = 16974150; // 0x1030146
@@ -2215,7 +2220,6 @@ package android {
field public static final int Widget_Holo_EditText = 16973971; // 0x1030093
field public static final int Widget_Holo_ExpandableListView = 16973972; // 0x1030094
field public static final int Widget_Holo_FastScroll = 16974339; // 0x1030203
- field public static final int Widget_Holo_FragmentBreadCrumbs = 16974340; // 0x1030204
field public static final int Widget_Holo_GridView = 16973973; // 0x1030095
field public static final int Widget_Holo_HorizontalScrollView = 16973988; // 0x10300a4
field public static final int Widget_Holo_ImageButton = 16973974; // 0x1030096
@@ -2236,7 +2240,7 @@ package android {
field public static final int Widget_Holo_Light_ActionMode_Inverse = 16974119; // 0x1030127
field public static final int Widget_Holo_Light_AutoCompleteTextView = 16974011; // 0x10300bb
field public static final int Widget_Holo_Light_Button = 16974006; // 0x10300b6
- field public static final int Widget_Holo_Light_Button_Borderless = 16974342; // 0x1030206
+ field public static final int Widget_Holo_Light_Button_Borderless = 16974341; // 0x1030205
field public static final int Widget_Holo_Light_Button_Borderless_Small = 16974107; // 0x103011b
field public static final int Widget_Holo_Light_Button_Inset = 16974008; // 0x10300b8
field public static final int Widget_Holo_Light_Button_Small = 16974007; // 0x10300b7
@@ -2250,8 +2254,7 @@ package android {
field public static final int Widget_Holo_Light_DropDownItem_Spinner = 16974041; // 0x10300d9
field public static final int Widget_Holo_Light_EditText = 16974014; // 0x10300be
field public static final int Widget_Holo_Light_ExpandableListView = 16974015; // 0x10300bf
- field public static final int Widget_Holo_Light_FastScroll = 16974343; // 0x1030207
- field public static final int Widget_Holo_Light_FragmentBreadCrumbs = 16974344; // 0x1030208
+ field public static final int Widget_Holo_Light_FastScroll = 16974342; // 0x1030206
field public static final int Widget_Holo_Light_GridView = 16974016; // 0x10300c0
field public static final int Widget_Holo_Light_HorizontalScrollView = 16974034; // 0x10300d2
field public static final int Widget_Holo_Light_ImageButton = 16974017; // 0x10300c1
@@ -2275,7 +2278,7 @@ package android {
field public static final int Widget_Holo_Light_ScrollView = 16974033; // 0x10300d1
field public static final int Widget_Holo_Light_SeekBar = 16974028; // 0x10300cc
field public static final int Widget_Holo_Light_Spinner = 16974035; // 0x10300d3
- field public static final int Widget_Holo_Light_StackView = 16974345; // 0x1030209
+ field public static final int Widget_Holo_Light_StackView = 16974343; // 0x1030207
field public static final int Widget_Holo_Light_Tab = 16974052; // 0x10300e4
field public static final int Widget_Holo_Light_TabWidget = 16974037; // 0x10300d5
field public static final int Widget_Holo_Light_TextView = 16974010; // 0x10300ba
@@ -2299,7 +2302,7 @@ package android {
field public static final int Widget_Holo_ScrollView = 16973987; // 0x10300a3
field public static final int Widget_Holo_SeekBar = 16973982; // 0x103009e
field public static final int Widget_Holo_Spinner = 16973989; // 0x10300a5
- field public static final int Widget_Holo_StackView = 16974341; // 0x1030205
+ field public static final int Widget_Holo_StackView = 16974340; // 0x1030204
field public static final int Widget_Holo_Tab = 16974051; // 0x10300e3
field public static final int Widget_Holo_TabWidget = 16973991; // 0x10300a7
field public static final int Widget_Holo_TextView = 16973967; // 0x103008f
@@ -2323,128 +2326,126 @@ package android {
field public static final int Widget_ProgressBar_Large_Inverse = 16973916; // 0x103005c
field public static final int Widget_ProgressBar_Small = 16973854; // 0x103001e
field public static final int Widget_ProgressBar_Small_Inverse = 16973917; // 0x103005d
- field public static final int Widget_Quantum = 16974419; // 0x1030253
- field public static final int Widget_Quantum_ActionBar = 16974420; // 0x1030254
- field public static final int Widget_Quantum_ActionBar_Solid = 16974421; // 0x1030255
- field public static final int Widget_Quantum_ActionBar_TabBar = 16974422; // 0x1030256
- field public static final int Widget_Quantum_ActionBar_TabText = 16974423; // 0x1030257
- field public static final int Widget_Quantum_ActionBar_TabView = 16974424; // 0x1030258
- field public static final int Widget_Quantum_ActionButton = 16974425; // 0x1030259
- field public static final int Widget_Quantum_ActionButton_CloseMode = 16974426; // 0x103025a
- field public static final int Widget_Quantum_ActionButton_Overflow = 16974427; // 0x103025b
- field public static final int Widget_Quantum_ActionMode = 16974428; // 0x103025c
- field public static final int Widget_Quantum_AutoCompleteTextView = 16974429; // 0x103025d
- field public static final int Widget_Quantum_Button = 16974430; // 0x103025e
- field public static final int Widget_Quantum_ButtonBar = 16974436; // 0x1030264
- field public static final int Widget_Quantum_ButtonBar_AlertDialog = 16974437; // 0x1030265
- field public static final int Widget_Quantum_Button_Borderless = 16974431; // 0x103025f
- field public static final int Widget_Quantum_Button_Borderless_Small = 16974432; // 0x1030260
- field public static final int Widget_Quantum_Button_Inset = 16974433; // 0x1030261
- field public static final int Widget_Quantum_Button_Small = 16974434; // 0x1030262
- field public static final int Widget_Quantum_Button_Toggle = 16974435; // 0x1030263
- field public static final int Widget_Quantum_CalendarView = 16974438; // 0x1030266
- field public static final int Widget_Quantum_CheckedTextView = 16974439; // 0x1030267
- field public static final int Widget_Quantum_CompoundButton_CheckBox = 16974440; // 0x1030268
- field public static final int Widget_Quantum_CompoundButton_RadioButton = 16974441; // 0x1030269
- field public static final int Widget_Quantum_CompoundButton_Star = 16974442; // 0x103026a
- field public static final int Widget_Quantum_DatePicker = 16974443; // 0x103026b
- field public static final int Widget_Quantum_DropDownItem = 16974444; // 0x103026c
- field public static final int Widget_Quantum_DropDownItem_Spinner = 16974445; // 0x103026d
- field public static final int Widget_Quantum_EditText = 16974446; // 0x103026e
- field public static final int Widget_Quantum_ExpandableListView = 16974447; // 0x103026f
- field public static final int Widget_Quantum_FastScroll = 16974448; // 0x1030270
- field public static final int Widget_Quantum_FragmentBreadCrumbs = 16974449; // 0x1030271
- field public static final int Widget_Quantum_GridView = 16974450; // 0x1030272
- field public static final int Widget_Quantum_HorizontalScrollView = 16974451; // 0x1030273
- field public static final int Widget_Quantum_ImageButton = 16974452; // 0x1030274
- field public static final int Widget_Quantum_Light = 16974479; // 0x103028f
- field public static final int Widget_Quantum_Light_ActionBar = 16974480; // 0x1030290
- field public static final int Widget_Quantum_Light_ActionBar_Solid = 16974481; // 0x1030291
- field public static final int Widget_Quantum_Light_ActionBar_TabBar = 16974482; // 0x1030292
- field public static final int Widget_Quantum_Light_ActionBar_TabText = 16974483; // 0x1030293
- field public static final int Widget_Quantum_Light_ActionBar_TabView = 16974484; // 0x1030294
- field public static final int Widget_Quantum_Light_ActionButton = 16974485; // 0x1030295
- field public static final int Widget_Quantum_Light_ActionButton_CloseMode = 16974486; // 0x1030296
- field public static final int Widget_Quantum_Light_ActionButton_Overflow = 16974487; // 0x1030297
- field public static final int Widget_Quantum_Light_ActionMode = 16974488; // 0x1030298
- field public static final int Widget_Quantum_Light_AutoCompleteTextView = 16974489; // 0x1030299
- field public static final int Widget_Quantum_Light_Button = 16974490; // 0x103029a
- field public static final int Widget_Quantum_Light_ButtonBar = 16974496; // 0x10302a0
- field public static final int Widget_Quantum_Light_ButtonBar_AlertDialog = 16974497; // 0x10302a1
- field public static final int Widget_Quantum_Light_Button_Borderless = 16974491; // 0x103029b
- field public static final int Widget_Quantum_Light_Button_Borderless_Small = 16974492; // 0x103029c
- field public static final int Widget_Quantum_Light_Button_Inset = 16974493; // 0x103029d
- field public static final int Widget_Quantum_Light_Button_Small = 16974494; // 0x103029e
- field public static final int Widget_Quantum_Light_Button_Toggle = 16974495; // 0x103029f
- field public static final int Widget_Quantum_Light_CalendarView = 16974498; // 0x10302a2
- field public static final int Widget_Quantum_Light_CheckedTextView = 16974499; // 0x10302a3
- field public static final int Widget_Quantum_Light_CompoundButton_CheckBox = 16974500; // 0x10302a4
- field public static final int Widget_Quantum_Light_CompoundButton_RadioButton = 16974501; // 0x10302a5
- field public static final int Widget_Quantum_Light_CompoundButton_Star = 16974502; // 0x10302a6
- field public static final int Widget_Quantum_Light_DropDownItem = 16974503; // 0x10302a7
- field public static final int Widget_Quantum_Light_DropDownItem_Spinner = 16974504; // 0x10302a8
- field public static final int Widget_Quantum_Light_EditText = 16974505; // 0x10302a9
- field public static final int Widget_Quantum_Light_ExpandableListView = 16974506; // 0x10302aa
- field public static final int Widget_Quantum_Light_FastScroll = 16974507; // 0x10302ab
- field public static final int Widget_Quantum_Light_FragmentBreadCrumbs = 16974508; // 0x10302ac
- field public static final int Widget_Quantum_Light_GridView = 16974509; // 0x10302ad
- field public static final int Widget_Quantum_Light_HorizontalScrollView = 16974510; // 0x10302ae
- field public static final int Widget_Quantum_Light_ImageButton = 16974511; // 0x10302af
- field public static final int Widget_Quantum_Light_ListPopupWindow = 16974512; // 0x10302b0
- field public static final int Widget_Quantum_Light_ListView = 16974513; // 0x10302b1
- field public static final int Widget_Quantum_Light_ListView_DropDown = 16974514; // 0x10302b2
- field public static final int Widget_Quantum_Light_MediaRouteButton = 16974515; // 0x10302b3
- field public static final int Widget_Quantum_Light_PopupMenu = 16974516; // 0x10302b4
- field public static final int Widget_Quantum_Light_PopupMenu_Overflow = 16974517; // 0x10302b5
- field public static final int Widget_Quantum_Light_PopupWindow = 16974518; // 0x10302b6
- field public static final int Widget_Quantum_Light_ProgressBar = 16974519; // 0x10302b7
- field public static final int Widget_Quantum_Light_ProgressBar_Horizontal = 16974520; // 0x10302b8
- field public static final int Widget_Quantum_Light_ProgressBar_Inverse = 16974521; // 0x10302b9
- field public static final int Widget_Quantum_Light_ProgressBar_Large = 16974522; // 0x10302ba
- field public static final int Widget_Quantum_Light_ProgressBar_Large_Inverse = 16974523; // 0x10302bb
- field public static final int Widget_Quantum_Light_ProgressBar_Small = 16974524; // 0x10302bc
- field public static final int Widget_Quantum_Light_ProgressBar_Small_Inverse = 16974525; // 0x10302bd
- field public static final int Widget_Quantum_Light_ProgressBar_Small_Title = 16974526; // 0x10302be
- field public static final int Widget_Quantum_Light_RatingBar = 16974527; // 0x10302bf
- field public static final int Widget_Quantum_Light_RatingBar_Indicator = 16974528; // 0x10302c0
- field public static final int Widget_Quantum_Light_RatingBar_Small = 16974529; // 0x10302c1
- field public static final int Widget_Quantum_Light_ScrollView = 16974530; // 0x10302c2
- field public static final int Widget_Quantum_Light_SeekBar = 16974531; // 0x10302c3
- field public static final int Widget_Quantum_Light_SegmentedButton = 16974532; // 0x10302c4
- field public static final int Widget_Quantum_Light_Spinner = 16974534; // 0x10302c6
- field public static final int Widget_Quantum_Light_StackView = 16974533; // 0x10302c5
- field public static final int Widget_Quantum_Light_Tab = 16974535; // 0x10302c7
- field public static final int Widget_Quantum_Light_TabWidget = 16974536; // 0x10302c8
- field public static final int Widget_Quantum_Light_TextView = 16974537; // 0x10302c9
- field public static final int Widget_Quantum_Light_TextView_SpinnerItem = 16974538; // 0x10302ca
- field public static final int Widget_Quantum_Light_WebTextView = 16974539; // 0x10302cb
- field public static final int Widget_Quantum_Light_WebView = 16974540; // 0x10302cc
- field public static final int Widget_Quantum_ListPopupWindow = 16974453; // 0x1030275
- field public static final int Widget_Quantum_ListView = 16974454; // 0x1030276
- field public static final int Widget_Quantum_ListView_DropDown = 16974455; // 0x1030277
- field public static final int Widget_Quantum_MediaRouteButton = 16974456; // 0x1030278
- field public static final int Widget_Quantum_PopupMenu = 16974457; // 0x1030279
- field public static final int Widget_Quantum_PopupMenu_Overflow = 16974458; // 0x103027a
- field public static final int Widget_Quantum_PopupWindow = 16974459; // 0x103027b
- field public static final int Widget_Quantum_ProgressBar = 16974460; // 0x103027c
- field public static final int Widget_Quantum_ProgressBar_Horizontal = 16974461; // 0x103027d
- field public static final int Widget_Quantum_ProgressBar_Large = 16974462; // 0x103027e
- field public static final int Widget_Quantum_ProgressBar_Small = 16974463; // 0x103027f
- field public static final int Widget_Quantum_ProgressBar_Small_Title = 16974464; // 0x1030280
- field public static final int Widget_Quantum_RatingBar = 16974465; // 0x1030281
- field public static final int Widget_Quantum_RatingBar_Indicator = 16974466; // 0x1030282
- field public static final int Widget_Quantum_RatingBar_Small = 16974467; // 0x1030283
- field public static final int Widget_Quantum_ScrollView = 16974468; // 0x1030284
- field public static final int Widget_Quantum_SeekBar = 16974469; // 0x1030285
- field public static final int Widget_Quantum_SegmentedButton = 16974470; // 0x1030286
- field public static final int Widget_Quantum_Spinner = 16974472; // 0x1030288
- field public static final int Widget_Quantum_StackView = 16974471; // 0x1030287
- field public static final int Widget_Quantum_Tab = 16974473; // 0x1030289
- field public static final int Widget_Quantum_TabWidget = 16974474; // 0x103028a
- field public static final int Widget_Quantum_TextView = 16974475; // 0x103028b
- field public static final int Widget_Quantum_TextView_SpinnerItem = 16974476; // 0x103028c
- field public static final int Widget_Quantum_WebTextView = 16974477; // 0x103028d
- field public static final int Widget_Quantum_WebView = 16974478; // 0x103028e
+ field public static final int Widget_Quantum = 16974415; // 0x103024f
+ field public static final int Widget_Quantum_ActionBar = 16974416; // 0x1030250
+ field public static final int Widget_Quantum_ActionBar_Solid = 16974417; // 0x1030251
+ field public static final int Widget_Quantum_ActionBar_TabBar = 16974418; // 0x1030252
+ field public static final int Widget_Quantum_ActionBar_TabText = 16974419; // 0x1030253
+ field public static final int Widget_Quantum_ActionBar_TabView = 16974420; // 0x1030254
+ field public static final int Widget_Quantum_ActionButton = 16974421; // 0x1030255
+ field public static final int Widget_Quantum_ActionButton_CloseMode = 16974422; // 0x1030256
+ field public static final int Widget_Quantum_ActionButton_Overflow = 16974423; // 0x1030257
+ field public static final int Widget_Quantum_ActionMode = 16974424; // 0x1030258
+ field public static final int Widget_Quantum_AutoCompleteTextView = 16974425; // 0x1030259
+ field public static final int Widget_Quantum_Button = 16974426; // 0x103025a
+ field public static final int Widget_Quantum_ButtonBar = 16974432; // 0x1030260
+ field public static final int Widget_Quantum_ButtonBar_AlertDialog = 16974433; // 0x1030261
+ field public static final int Widget_Quantum_Button_Borderless = 16974427; // 0x103025b
+ field public static final int Widget_Quantum_Button_Borderless_Small = 16974428; // 0x103025c
+ field public static final int Widget_Quantum_Button_Inset = 16974429; // 0x103025d
+ field public static final int Widget_Quantum_Button_Small = 16974430; // 0x103025e
+ field public static final int Widget_Quantum_Button_Toggle = 16974431; // 0x103025f
+ field public static final int Widget_Quantum_CalendarView = 16974434; // 0x1030262
+ field public static final int Widget_Quantum_CheckedTextView = 16974435; // 0x1030263
+ field public static final int Widget_Quantum_CompoundButton_CheckBox = 16974436; // 0x1030264
+ field public static final int Widget_Quantum_CompoundButton_RadioButton = 16974437; // 0x1030265
+ field public static final int Widget_Quantum_CompoundButton_Star = 16974438; // 0x1030266
+ field public static final int Widget_Quantum_DatePicker = 16974439; // 0x1030267
+ field public static final int Widget_Quantum_DropDownItem = 16974440; // 0x1030268
+ field public static final int Widget_Quantum_DropDownItem_Spinner = 16974441; // 0x1030269
+ field public static final int Widget_Quantum_EditText = 16974442; // 0x103026a
+ field public static final int Widget_Quantum_ExpandableListView = 16974443; // 0x103026b
+ field public static final int Widget_Quantum_FastScroll = 16974444; // 0x103026c
+ field public static final int Widget_Quantum_GridView = 16974445; // 0x103026d
+ field public static final int Widget_Quantum_HorizontalScrollView = 16974446; // 0x103026e
+ field public static final int Widget_Quantum_ImageButton = 16974447; // 0x103026f
+ field public static final int Widget_Quantum_Light = 16974474; // 0x103028a
+ field public static final int Widget_Quantum_Light_ActionBar = 16974475; // 0x103028b
+ field public static final int Widget_Quantum_Light_ActionBar_Solid = 16974476; // 0x103028c
+ field public static final int Widget_Quantum_Light_ActionBar_TabBar = 16974477; // 0x103028d
+ field public static final int Widget_Quantum_Light_ActionBar_TabText = 16974478; // 0x103028e
+ field public static final int Widget_Quantum_Light_ActionBar_TabView = 16974479; // 0x103028f
+ field public static final int Widget_Quantum_Light_ActionButton = 16974480; // 0x1030290
+ field public static final int Widget_Quantum_Light_ActionButton_CloseMode = 16974481; // 0x1030291
+ field public static final int Widget_Quantum_Light_ActionButton_Overflow = 16974482; // 0x1030292
+ field public static final int Widget_Quantum_Light_ActionMode = 16974483; // 0x1030293
+ field public static final int Widget_Quantum_Light_AutoCompleteTextView = 16974484; // 0x1030294
+ field public static final int Widget_Quantum_Light_Button = 16974485; // 0x1030295
+ field public static final int Widget_Quantum_Light_ButtonBar = 16974491; // 0x103029b
+ field public static final int Widget_Quantum_Light_ButtonBar_AlertDialog = 16974492; // 0x103029c
+ field public static final int Widget_Quantum_Light_Button_Borderless = 16974486; // 0x1030296
+ field public static final int Widget_Quantum_Light_Button_Borderless_Small = 16974487; // 0x1030297
+ field public static final int Widget_Quantum_Light_Button_Inset = 16974488; // 0x1030298
+ field public static final int Widget_Quantum_Light_Button_Small = 16974489; // 0x1030299
+ field public static final int Widget_Quantum_Light_Button_Toggle = 16974490; // 0x103029a
+ field public static final int Widget_Quantum_Light_CalendarView = 16974493; // 0x103029d
+ field public static final int Widget_Quantum_Light_CheckedTextView = 16974494; // 0x103029e
+ field public static final int Widget_Quantum_Light_CompoundButton_CheckBox = 16974495; // 0x103029f
+ field public static final int Widget_Quantum_Light_CompoundButton_RadioButton = 16974496; // 0x10302a0
+ field public static final int Widget_Quantum_Light_CompoundButton_Star = 16974497; // 0x10302a1
+ field public static final int Widget_Quantum_Light_DropDownItem = 16974498; // 0x10302a2
+ field public static final int Widget_Quantum_Light_DropDownItem_Spinner = 16974499; // 0x10302a3
+ field public static final int Widget_Quantum_Light_EditText = 16974500; // 0x10302a4
+ field public static final int Widget_Quantum_Light_ExpandableListView = 16974501; // 0x10302a5
+ field public static final int Widget_Quantum_Light_FastScroll = 16974502; // 0x10302a6
+ field public static final int Widget_Quantum_Light_GridView = 16974503; // 0x10302a7
+ field public static final int Widget_Quantum_Light_HorizontalScrollView = 16974504; // 0x10302a8
+ field public static final int Widget_Quantum_Light_ImageButton = 16974505; // 0x10302a9
+ field public static final int Widget_Quantum_Light_ListPopupWindow = 16974506; // 0x10302aa
+ field public static final int Widget_Quantum_Light_ListView = 16974507; // 0x10302ab
+ field public static final int Widget_Quantum_Light_ListView_DropDown = 16974508; // 0x10302ac
+ field public static final int Widget_Quantum_Light_MediaRouteButton = 16974509; // 0x10302ad
+ field public static final int Widget_Quantum_Light_PopupMenu = 16974510; // 0x10302ae
+ field public static final int Widget_Quantum_Light_PopupMenu_Overflow = 16974511; // 0x10302af
+ field public static final int Widget_Quantum_Light_PopupWindow = 16974512; // 0x10302b0
+ field public static final int Widget_Quantum_Light_ProgressBar = 16974513; // 0x10302b1
+ field public static final int Widget_Quantum_Light_ProgressBar_Horizontal = 16974514; // 0x10302b2
+ field public static final int Widget_Quantum_Light_ProgressBar_Inverse = 16974515; // 0x10302b3
+ field public static final int Widget_Quantum_Light_ProgressBar_Large = 16974516; // 0x10302b4
+ field public static final int Widget_Quantum_Light_ProgressBar_Large_Inverse = 16974517; // 0x10302b5
+ field public static final int Widget_Quantum_Light_ProgressBar_Small = 16974518; // 0x10302b6
+ field public static final int Widget_Quantum_Light_ProgressBar_Small_Inverse = 16974519; // 0x10302b7
+ field public static final int Widget_Quantum_Light_ProgressBar_Small_Title = 16974520; // 0x10302b8
+ field public static final int Widget_Quantum_Light_RatingBar = 16974521; // 0x10302b9
+ field public static final int Widget_Quantum_Light_RatingBar_Indicator = 16974522; // 0x10302ba
+ field public static final int Widget_Quantum_Light_RatingBar_Small = 16974523; // 0x10302bb
+ field public static final int Widget_Quantum_Light_ScrollView = 16974524; // 0x10302bc
+ field public static final int Widget_Quantum_Light_SeekBar = 16974525; // 0x10302bd
+ field public static final int Widget_Quantum_Light_SegmentedButton = 16974526; // 0x10302be
+ field public static final int Widget_Quantum_Light_Spinner = 16974528; // 0x10302c0
+ field public static final int Widget_Quantum_Light_StackView = 16974527; // 0x10302bf
+ field public static final int Widget_Quantum_Light_Tab = 16974529; // 0x10302c1
+ field public static final int Widget_Quantum_Light_TabWidget = 16974530; // 0x10302c2
+ field public static final int Widget_Quantum_Light_TextView = 16974531; // 0x10302c3
+ field public static final int Widget_Quantum_Light_TextView_SpinnerItem = 16974532; // 0x10302c4
+ field public static final int Widget_Quantum_Light_WebTextView = 16974533; // 0x10302c5
+ field public static final int Widget_Quantum_Light_WebView = 16974534; // 0x10302c6
+ field public static final int Widget_Quantum_ListPopupWindow = 16974448; // 0x1030270
+ field public static final int Widget_Quantum_ListView = 16974449; // 0x1030271
+ field public static final int Widget_Quantum_ListView_DropDown = 16974450; // 0x1030272
+ field public static final int Widget_Quantum_MediaRouteButton = 16974451; // 0x1030273
+ field public static final int Widget_Quantum_PopupMenu = 16974452; // 0x1030274
+ field public static final int Widget_Quantum_PopupMenu_Overflow = 16974453; // 0x1030275
+ field public static final int Widget_Quantum_PopupWindow = 16974454; // 0x1030276
+ field public static final int Widget_Quantum_ProgressBar = 16974455; // 0x1030277
+ field public static final int Widget_Quantum_ProgressBar_Horizontal = 16974456; // 0x1030278
+ field public static final int Widget_Quantum_ProgressBar_Large = 16974457; // 0x1030279
+ field public static final int Widget_Quantum_ProgressBar_Small = 16974458; // 0x103027a
+ field public static final int Widget_Quantum_ProgressBar_Small_Title = 16974459; // 0x103027b
+ field public static final int Widget_Quantum_RatingBar = 16974460; // 0x103027c
+ field public static final int Widget_Quantum_RatingBar_Indicator = 16974461; // 0x103027d
+ field public static final int Widget_Quantum_RatingBar_Small = 16974462; // 0x103027e
+ field public static final int Widget_Quantum_ScrollView = 16974463; // 0x103027f
+ field public static final int Widget_Quantum_SeekBar = 16974464; // 0x1030280
+ field public static final int Widget_Quantum_SegmentedButton = 16974465; // 0x1030281
+ field public static final int Widget_Quantum_Spinner = 16974467; // 0x1030283
+ field public static final int Widget_Quantum_StackView = 16974466; // 0x1030282
+ field public static final int Widget_Quantum_Tab = 16974468; // 0x1030284
+ field public static final int Widget_Quantum_TabWidget = 16974469; // 0x1030285
+ field public static final int Widget_Quantum_TextView = 16974470; // 0x1030286
+ field public static final int Widget_Quantum_TextView_SpinnerItem = 16974471; // 0x1030287
+ field public static final int Widget_Quantum_WebTextView = 16974472; // 0x1030288
+ field public static final int Widget_Quantum_WebView = 16974473; // 0x1030289
field public static final int Widget_RatingBar = 16973857; // 0x1030021
field public static final int Widget_ScrollView = 16973869; // 0x103002d
field public static final int Widget_SeekBar = 16973856; // 0x1030020
@@ -3256,6 +3257,7 @@ package android.app {
method public boolean navigateUpToFromChild(android.app.Activity, android.content.Intent);
method public void onActionModeFinished(android.view.ActionMode);
method public void onActionModeStarted(android.view.ActionMode);
+ method protected void onActivityReenter(int, android.content.Intent);
method protected void onActivityResult(int, int, android.content.Intent);
method public void onAttachFragment(android.app.Fragment);
method public void onAttachedToWindow();
@@ -3334,7 +3336,6 @@ package android.app {
method public final boolean requestWindowFeature(int);
method public final void runOnUiThread(java.lang.Runnable);
method public void setActionBar(android.widget.Toolbar);
- method public void setActivityTransitionListener(android.app.ActivityOptions.ActivityTransitionListener);
method public void setContentTransitionManager(android.transition.TransitionManager);
method public void setContentView(int);
method public void setContentView(android.view.View);
@@ -3356,6 +3357,7 @@ package android.app {
method public final void setResult(int);
method public final void setResult(int, android.content.Intent);
method public final void setSecondaryProgress(int);
+ method public void setSharedElementListener(android.app.SharedElementListener);
method public void setTitle(java.lang.CharSequence);
method public void setTitle(int);
method public deprecated void setTitleColor(int);
@@ -3575,28 +3577,13 @@ package android.app {
public class ActivityOptions {
method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
method public static android.app.ActivityOptions makeScaleUpAnimation(android.view.View, int, int, int, int);
- method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.view.Window, android.view.View, java.lang.String);
- method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.view.Window, android.app.ActivityOptions.ActivityTransitionListener);
+ method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.app.Activity, android.view.View, java.lang.String);
+ method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.app.Activity, android.util.Pair<android.view.View, java.lang.String>...);
method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
method public android.os.Bundle toBundle();
method public void update(android.app.ActivityOptions);
}
- public static class ActivityOptions.ActivityTransitionListener {
- ctor public ActivityOptions.ActivityTransitionListener();
- method public android.util.Pair<android.view.View, java.lang.String>[] getSharedElementsMapping();
- method public boolean handleRejectedSharedElements(java.util.List<android.view.View>);
- method public void onCaptureSharedElementEnd(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
- method public void onCaptureSharedElementStart(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
- method public void onEnterReady();
- method public void onExitTransitionComplete();
- method public void onRemoteExitComplete();
- method public void onSharedElementExitTransitionComplete();
- method public void onSharedElementTransferred(java.util.List<java.lang.String>, java.util.List<android.view.View>);
- method public void onStartEnterTransition(java.util.List<java.lang.String>, java.util.List<android.view.View>);
- method public void onStartExitTransition(java.util.List<java.lang.String>, java.util.List<android.view.View>);
- }
-
public class AlarmManager {
method public void cancel(android.app.PendingIntent);
method public void set(int, long, android.app.PendingIntent);
@@ -4115,11 +4102,10 @@ package android.app {
field public static final android.os.Parcelable.ClassLoaderCreator CREATOR;
}
- public class FragmentBreadCrumbs extends android.view.ViewGroup implements android.app.FragmentManager.OnBackStackChangedListener {
+ public deprecated class FragmentBreadCrumbs extends android.view.ViewGroup implements android.app.FragmentManager.OnBackStackChangedListener {
ctor public FragmentBreadCrumbs(android.content.Context);
ctor public FragmentBreadCrumbs(android.content.Context, android.util.AttributeSet);
ctor public FragmentBreadCrumbs(android.content.Context, android.util.AttributeSet, int);
- ctor public FragmentBreadCrumbs(android.content.Context, android.util.AttributeSet, int, int);
method public void onBackStackChanged();
method protected void onLayout(boolean, int, int, int, int);
method public void setActivity(android.app.Activity);
@@ -4820,6 +4806,14 @@ package android.app {
field public static final int START_STICKY_COMPATIBILITY = 0; // 0x0
}
+ public class SharedElementListener {
+ ctor public SharedElementListener();
+ method public void handleRejectedSharedElements(java.util.List<android.view.View>);
+ method public void remapSharedElements(java.util.List<java.lang.String>, java.util.Map<java.lang.String, android.view.View>);
+ method public void setSharedElementEnd(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
+ method public void setSharedElementStart(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
+ }
+
public deprecated class TabActivity extends android.app.ActivityGroup {
ctor public TabActivity();
method public android.widget.TabHost getTabHost();
@@ -10094,7 +10088,7 @@ package android.graphics {
enum_constant public static final android.graphics.Interpolator.Result NORMAL;
}
- public class LayerRasterizer extends android.graphics.Rasterizer {
+ public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
ctor public LayerRasterizer();
method public void addLayer(android.graphics.Paint, float, float);
method public void addLayer(android.graphics.Paint);
@@ -10122,6 +10116,7 @@ package android.graphics {
ctor public Matrix(android.graphics.Matrix);
method public void getValues(float[]);
method public boolean invert(android.graphics.Matrix);
+ method public boolean isAffine();
method public boolean isIdentity();
method public void mapPoints(float[], int, float[], int, int);
method public void mapPoints(float[], float[]);
@@ -10219,7 +10214,9 @@ package android.graphics {
public final class Outline {
ctor public Outline();
ctor public Outline(android.graphics.Outline);
+ method public boolean canClip();
method public boolean isValid();
+ method public void reset();
method public void set(android.graphics.Outline);
method public void setConvexPath(android.graphics.Path);
method public void setOval(int, int, int, int);
@@ -10253,7 +10250,7 @@ package android.graphics {
method public int getHinting();
method public android.graphics.MaskFilter getMaskFilter();
method public android.graphics.PathEffect getPathEffect();
- method public android.graphics.Rasterizer getRasterizer();
+ method public deprecated android.graphics.Rasterizer getRasterizer();
method public android.graphics.Shader getShader();
method public android.graphics.Paint.Cap getStrokeCap();
method public android.graphics.Paint.Join getStrokeJoin();
@@ -10304,7 +10301,7 @@ package android.graphics {
method public void setLinearText(boolean);
method public android.graphics.MaskFilter setMaskFilter(android.graphics.MaskFilter);
method public android.graphics.PathEffect setPathEffect(android.graphics.PathEffect);
- method public android.graphics.Rasterizer setRasterizer(android.graphics.Rasterizer);
+ method public deprecated android.graphics.Rasterizer setRasterizer(android.graphics.Rasterizer);
method public android.graphics.Shader setShader(android.graphics.Shader);
method public void setShadowLayer(float, float, float, int);
method public void setStrikeThruText(boolean);
@@ -10613,7 +10610,7 @@ package android.graphics {
ctor public RadialGradient(float, float, float, int, int, android.graphics.Shader.TileMode);
}
- public class Rasterizer {
+ public deprecated class Rasterizer {
ctor public Rasterizer();
}
@@ -11361,6 +11358,24 @@ package android.graphics.pdf {
method public android.graphics.pdf.PdfDocument.PageInfo.Builder setContentRect(android.graphics.Rect);
}
+ public final class PdfRenderer implements java.lang.AutoCloseable {
+ ctor public PdfRenderer(android.os.ParcelFileDescriptor) throws java.io.IOException;
+ method public void close();
+ method public void closePage(android.graphics.pdf.PdfRenderer.Page);
+ method public int getPageCount();
+ method public android.graphics.pdf.PdfRenderer.Page openPage(int);
+ method public boolean shouldScaleForPrinting();
+ }
+
+ public final class PdfRenderer.Page {
+ method public int getHeight();
+ method public int getIndex();
+ method public int getWidth();
+ method public void render(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Matrix, int);
+ field public static final int RENDER_MODE_FOR_DISPLAY = 1; // 0x1
+ field public static final int RENDER_MODE_FOR_PRINT = 2; // 0x2
+ }
+
}
package android.hardware {
@@ -11864,16 +11879,8 @@ package android.hardware.camera2 {
field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_MAX_NUM_OUTPUT_STREAMS;
field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PARTIAL_RESULT_COUNT;
field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PIPELINE_MAX_DEPTH;
- field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_FORMATS;
- field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP;
- field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_JPEG_MIN_DURATIONS;
- field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_JPEG_SIZES;
field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
- field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
- field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS;
- field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_PROCESSED_SIZES;
- field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_STALL_DURATIONS;
- field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
+ field public static final android.hardware.camera2.CameraMetadata.Key SCALER_STREAM_CONFIGURATION_MAP;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_AVAILABLE_TEST_PATTERN_MODES;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_BASE_GAIN_FACTOR;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_BLACK_LEVEL_PATTERN;
@@ -12083,8 +12090,6 @@ package android.hardware.camera2 {
field public static final int REQUEST_AVAILABLE_CAPABILITIES_DNG = 5; // 0x5
field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 2; // 0x2
field public static final int REQUEST_AVAILABLE_CAPABILITIES_ZSL = 4; // 0x4
- field public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT = 1; // 0x1
- field public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT = 0; // 0x0
field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR = 3; // 0x3
field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG = 2; // 0x2
field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG = 1; // 0x1
@@ -12365,6 +12370,22 @@ package android.hardware.camera2 {
method public final int getWidth();
}
+ public final class TonemapCurve {
+ method public void copyColorCurve(int, float[], int);
+ method public android.graphics.PointF getPoint(int, int);
+ method public int getPointCount(int);
+ field public static final int CHANNEL_BLUE = 2; // 0x2
+ field public static final int CHANNEL_GREEN = 1; // 0x1
+ field public static final int CHANNEL_RED = 0; // 0x0
+ field public static final float LEVEL_BLACK = 0.0f;
+ field public static final float LEVEL_WHITE = 1.0f;
+ field public static final int POINT_SIZE = 2; // 0x2
+ }
+
+}
+
+package android.hardware.camera2.params {
+
public final class StreamConfigurationMap {
method public final int[] getOutputFormats();
method public long getOutputMinFrameDuration(int, android.util.Size);
@@ -12378,18 +12399,6 @@ package android.hardware.camera2 {
method public boolean isOutputSupportedFor(android.view.Surface);
}
- public final class TonemapCurve {
- method public void copyColorCurve(int, float[], int);
- method public android.graphics.PointF getPoint(int, int);
- method public int getPointCount(int);
- field public static final int CHANNEL_BLUE = 2; // 0x2
- field public static final int CHANNEL_GREEN = 1; // 0x1
- field public static final int CHANNEL_RED = 0; // 0x0
- field public static final float LEVEL_BLACK = 0.0f;
- field public static final float LEVEL_WHITE = 1.0f;
- field public static final int POINT_SIZE = 2; // 0x2
- }
-
}
package android.hardware.display {
@@ -12467,16 +12476,17 @@ package android.hardware.hdmi {
field public static final int MESSAGE_FEATURE_ABORT = 0; // 0x0
field public static final int MESSAGE_GET_CEC_VERSION = 159; // 0x9f
field public static final int MESSAGE_GET_MENU_LANGUAGE = 145; // 0x91
- field public static final int MESSAGE_GET_OSD_NAME = 70; // 0x46
field public static final int MESSAGE_GIVE_AUDIO_STATUS = 113; // 0x71
field public static final int MESSAGE_GIVE_DECK_STATUS = 26; // 0x1a
field public static final int MESSAGE_GIVE_DEVICE_POWER_STATUS = 143; // 0x8f
field public static final int MESSAGE_GIVE_DEVICE_VENDOR_ID = 140; // 0x8c
+ field public static final int MESSAGE_GIVE_OSD_NAME = 70; // 0x46
field public static final int MESSAGE_GIVE_PHYSICAL_ADDRESS = 131; // 0x83
field public static final int MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS = 125; // 0x7d
field public static final int MESSAGE_GIVE_TUNER_DEVICE_STATUS = 8; // 0x8
field public static final int MESSAGE_IMAGE_VIEW_ON = 4; // 0x4
field public static final int MESSAGE_INACTIVE_SOURCE = 157; // 0x9d
+ field public static final int MESSAGE_INITIATE_ARC = 192; // 0xc0
field public static final int MESSAGE_MENU_REQUEST = 141; // 0x8d
field public static final int MESSAGE_MENU_STATUS = 142; // 0x8e
field public static final int MESSAGE_PLAY = 65; // 0x41
@@ -12484,10 +12494,14 @@ package android.hardware.hdmi {
field public static final int MESSAGE_RECORD_ON = 9; // 0x9
field public static final int MESSAGE_RECORD_STATUS = 10; // 0xa
field public static final int MESSAGE_RECORD_TV_SCREEN = 15; // 0xf
+ field public static final int MESSAGE_REPORT_ARC_INITIATED = 193; // 0xc1
+ field public static final int MESSAGE_REPORT_ARC_TERMINATED = 194; // 0xc2
field public static final int MESSAGE_REPORT_AUDIO_STATUS = 122; // 0x7a
field public static final int MESSAGE_REPORT_PHYSICAL_ADDRESS = 132; // 0x84
field public static final int MESSAGE_REPORT_POWER_STATUS = 144; // 0x90
field public static final int MESSAGE_REQUEST_ACTIVE_SOURCE = 133; // 0x85
+ field public static final int MESSAGE_REQUEST_ARC_INITIATION = 195; // 0xc3
+ field public static final int MESSAGE_REQUEST_ARC_TERMINATION = 196; // 0xc4
field public static final int MESSAGE_ROUTING_CHANGE = 128; // 0x80
field public static final int MESSAGE_ROUTING_INFORMATION = 129; // 0x81
field public static final int MESSAGE_SELECT_ANALOG_SERVICE = 146; // 0x92
@@ -12505,6 +12519,7 @@ package android.hardware.hdmi {
field public static final int MESSAGE_STANDBY = 54; // 0x36
field public static final int MESSAGE_SYSTEM_AUDIO_MODE_REQUEST = 112; // 0x70
field public static final int MESSAGE_SYSTEM_AUDIO_MODE_STATUS = 126; // 0x7e
+ field public static final int MESSAGE_TERMINATE_ARC = 197; // 0xc5
field public static final int MESSAGE_TEXT_VIEW_ON = 13; // 0xd
field public static final int MESSAGE_TIMER_CLEARED_STATUS = 67; // 0x43
field public static final int MESSAGE_TIMER_STATUS = 53; // 0x35
@@ -15558,7 +15573,7 @@ package android.media.session {
method public void addCallback(android.media.session.Session.Callback);
method public void addCallback(android.media.session.Session.Callback, android.os.Handler);
method public void connect(android.media.session.RouteInfo, android.media.session.RouteOptions);
- method public void disconnect(android.media.session.RouteInfo);
+ method public void disconnect();
method public android.media.session.SessionToken getSessionToken();
method public android.media.session.TransportPerformer getTransportPerformer();
method public boolean isActive();
@@ -15568,6 +15583,11 @@ package android.media.session {
method public void setActive(boolean);
method public void setFlags(int);
method public void setRouteOptions(java.util.List<android.media.session.RouteOptions>);
+ field public static final int DISCONNECT_REASON_PROVIDER_DISCONNECTED = 2; // 0x2
+ field public static final int DISCONNECT_REASON_ROUTE_CHANGED = 3; // 0x3
+ field public static final int DISCONNECT_REASON_SESSION_DESTROYED = 5; // 0x5
+ field public static final int DISCONNECT_REASON_SESSION_DISCONNECTED = 4; // 0x4
+ field public static final int DISCONNECT_REASON_USER_STOPPING = 1; // 0x1
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
@@ -19564,6 +19584,7 @@ package android.os {
public class BatteryProperty implements android.os.Parcelable {
method public int describeContents();
method public int getInt();
+ method public long getLong();
method public void readFromParcel(android.os.Parcel);
method public void writeToParcel(android.os.Parcel, int);
field public static final int CAPACITY = 4; // 0x4
@@ -19571,6 +19592,7 @@ package android.os {
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int CURRENT_AVERAGE = 3; // 0x3
field public static final int CURRENT_NOW = 2; // 0x2
+ field public static final int ENERGY_COUNTER = 4; // 0x4
}
public class Binder implements android.os.IBinder {
@@ -29362,8 +29384,13 @@ package android.transition {
method public android.transition.Transition setDuration(long);
method public void setEpicenterCallback(android.transition.Transition.EpicenterCallback);
method public android.transition.Transition setInterpolator(android.animation.TimeInterpolator);
+ method public void setMatchOrder(int...);
method public void setPropagation(android.transition.TransitionPropagation);
method public android.transition.Transition setStartDelay(long);
+ field public static final int MATCH_ID = 3; // 0x3
+ field public static final int MATCH_INSTANCE = 1; // 0x1
+ field public static final int MATCH_ITEM_ID = 4; // 0x4
+ field public static final int MATCH_VIEW_NAME = 2; // 0x2
}
public static abstract class Transition.EpicenterCallback {
@@ -32559,8 +32586,10 @@ package android.view {
method protected final int getForcedWindowFlags();
method public abstract android.view.LayoutInflater getLayoutInflater();
method protected final int getLocalFeatures();
+ method public abstract int getNavigationBarColor();
method public android.transition.Transition getSharedElementEnterTransition();
method public android.transition.Transition getSharedElementExitTransition();
+ method public abstract int getStatusBarColor();
method public android.transition.TransitionManager getTransitionManager();
method public abstract int getVolumeControlStream();
method public android.view.WindowManager getWindowManager();
@@ -32612,9 +32641,11 @@ package android.view {
method public void setLayout(int, int);
method public void setLocalFocus(boolean, boolean);
method public void setLogo(int);
+ method public abstract void setNavigationBarColor(int);
method public void setSharedElementEnterTransition(android.transition.Transition);
method public void setSharedElementExitTransition(android.transition.Transition);
method public void setSoftInputMode(int);
+ method public abstract void setStatusBarColor(int);
method public abstract void setTitle(java.lang.CharSequence);
method public abstract deprecated void setTitleColor(int);
method public void setTransitionManager(android.transition.TransitionManager);
@@ -32772,6 +32803,7 @@ package android.view {
field public static final int FLAG_DIM_BEHIND = 2; // 0x2
field public static final int FLAG_DISMISS_KEYGUARD = 4194304; // 0x400000
field public static final deprecated int FLAG_DITHER = 4096; // 0x1000
+ field public static final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = -2147483648; // 0x80000000
field public static final int FLAG_FORCE_NOT_FULLSCREEN = 2048; // 0x800
field public static final int FLAG_FULLSCREEN = 1024; // 0x400
field public static final int FLAG_HARDWARE_ACCELERATED = 16777216; // 0x1000000
@@ -32962,7 +32994,8 @@ package android.view.accessibility {
}
public class AccessibilityNodeInfo implements android.os.Parcelable {
- method public void addAction(int);
+ method public void addAction(android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction);
+ method public deprecated void addAction(int);
method public void addChild(android.view.View);
method public void addChild(android.view.View, int);
method public boolean canOpenPopup();
@@ -32971,7 +33004,8 @@ package android.view.accessibility {
method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(java.lang.String);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
method public android.view.accessibility.AccessibilityNodeInfo focusSearch(int);
- method public int getActions();
+ method public java.util.List<android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction> getActionList();
+ method public deprecated int getActions();
method public void getBoundsInParent(android.graphics.Rect);
method public void getBoundsInScreen(android.graphics.Rect);
method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
@@ -33019,7 +33053,8 @@ package android.view.accessibility {
method public boolean performAction(int, android.os.Bundle);
method public void recycle();
method public boolean refresh();
- method public void removeAction(int);
+ method public deprecated void removeAction(int);
+ method public boolean removeAction(android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction);
method public boolean removeChild(android.view.View);
method public boolean removeChild(android.view.View, int);
method public void setAccessibilityFocused(boolean);
@@ -33100,6 +33135,34 @@ package android.view.accessibility {
field public static final int MOVEMENT_GRANULARITY_WORD = 2; // 0x2
}
+ public static final class AccessibilityNodeInfo.AccessibilityAction {
+ ctor public AccessibilityNodeInfo.AccessibilityAction(int, java.lang.CharSequence);
+ method public int getId();
+ method public java.lang.CharSequence getLabel();
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_ACCESSIBILITY_FOCUS;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_CLEAR_FOCUS;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_CLEAR_SELECTION;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_CLICK;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_COLLAPSE;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_COPY;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_CUT;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_DISMISS;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_EXPAND;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_FOCUS;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_LONG_CLICK;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_NEXT_AT_MOVEMENT_GRANULARITY;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_NEXT_HTML_ELEMENT;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PASTE;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PREVIOUS_HTML_ELEMENT;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SCROLL_BACKWARD;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SCROLL_FORWARD;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SELECT;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_SELECTION;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_TEXT;
+ }
+
public static final class AccessibilityNodeInfo.CollectionInfo {
method public int getColumnCount();
method public int getRowCount();
@@ -36900,6 +36963,10 @@ package android.widget {
ctor public Toolbar(android.content.Context, android.util.AttributeSet);
ctor public Toolbar(android.content.Context, android.util.AttributeSet, int);
ctor public Toolbar(android.content.Context, android.util.AttributeSet, int, int);
+ method public int getContentInsetEnd();
+ method public int getContentInsetLeft();
+ method public int getContentInsetRight();
+ method public int getContentInsetStart();
method public android.graphics.drawable.Drawable getLogo();
method public java.lang.CharSequence getLogoDescription();
method public android.view.Menu getMenu();
@@ -36908,6 +36975,8 @@ package android.widget {
method public java.lang.CharSequence getTitle();
method public void inflateMenu(int);
method protected void onLayout(boolean, int, int, int, int);
+ method public void setContentInsetsAbsolute(int, int);
+ method public void setContentInsetsRelative(int, int);
method public void setLogo(int);
method public void setLogo(android.graphics.drawable.Drawable);
method public void setLogoDescription(int);
diff --git a/core/java/android/alsa/AlsaCardsParser.java b/core/java/android/alsa/AlsaCardsParser.java
index f9af979..8b44881 100644
--- a/core/java/android/alsa/AlsaCardsParser.java
+++ b/core/java/android/alsa/AlsaCardsParser.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.alsascan;
+package android.alsa;
import android.util.Slog;
import java.io.BufferedReader;
diff --git a/core/java/android/alsa/AlsaDevicesParser.java b/core/java/android/alsa/AlsaDevicesParser.java
index 094c8a2..82cc1ae 100644
--- a/core/java/android/alsa/AlsaDevicesParser.java
+++ b/core/java/android/alsa/AlsaDevicesParser.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.alsascan;
+package android.alsa;
import android.util.Slog;
import java.io.BufferedReader;
diff --git a/core/java/android/alsa/LineTokenizer.java b/core/java/android/alsa/LineTokenizer.java
index c138fc5..78c91b5 100644
--- a/core/java/android/alsa/LineTokenizer.java
+++ b/core/java/android/alsa/LineTokenizer.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.alsascan;
+package android.alsa;
/**
* @hide
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 4a30b05..36c36a8 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -777,8 +777,9 @@ public class Activity extends ContextThemeWrapper
private Thread mUiThread;
final Handler mHandler = new Handler();
- private ActivityOptions mCalledActivityOptions;
- private EnterTransitionCoordinator mEnterTransitionCoordinator;
+
+ private ActivityTransitionState mActivityTransitionState = new ActivityTransitionState();
+ SharedElementListener mTransitionListener = new SharedElementListener();
/** Return the intent that started this activity. */
public Intent getIntent() {
@@ -1100,9 +1101,6 @@ public class Activity extends ContextThemeWrapper
mTitleReady = true;
onTitleChanged(getTitle(), getTitleColor());
}
- if (mEnterTransitionCoordinator != null) {
- mEnterTransitionCoordinator.readyToEnter();
- }
mCalled = true;
}
@@ -1149,12 +1147,6 @@ public class Activity extends ContextThemeWrapper
}
getApplication().dispatchActivityStarted(this);
-
- final ActivityOptions activityOptions = getActivityOptions();
- if (activityOptions != null &&
- activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
- mEnterTransitionCoordinator = activityOptions.createEnterActivityTransition(this);
- }
}
/**
@@ -1204,7 +1196,6 @@ public class Activity extends ContextThemeWrapper
protected void onResume() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
getApplication().dispatchActivityResumed(this);
- mCalledActivityOptions = null;
mCalled = true;
}
@@ -1279,6 +1270,7 @@ public class Activity extends ContextThemeWrapper
final void performSaveInstanceState(Bundle outState) {
onSaveInstanceState(outState);
saveManagedDialogs(outState);
+ mActivityTransitionState.saveState(outState);
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState);
}
@@ -1549,10 +1541,7 @@ public class Activity extends ContextThemeWrapper
protected void onStop() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this);
if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
- if (mCalledActivityOptions != null) {
- mCalledActivityOptions.dispatchActivityStopped();
- mCalledActivityOptions = null;
- }
+ mActivityTransitionState.onStop();
getApplication().dispatchActivityStopped(this);
mTranslucentCallback = null;
mCalled = true;
@@ -3650,7 +3639,7 @@ public class Activity extends ContextThemeWrapper
public void startActivityForResult(Intent intent, int requestCode) {
Bundle options = null;
if (mWindow.hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
- options = ActivityOptions.makeSceneTransitionAnimation(mWindow, null).toBundle();
+ options = ActivityOptions.makeSceneTransitionAnimation(this).toBundle();
}
startActivityForResult(intent, requestCode, options);
}
@@ -3691,9 +3680,7 @@ public class Activity extends ContextThemeWrapper
*/
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
if (options != null) {
- ActivityOptions activityOptions = new ActivityOptions(options);
- activityOptions.dispatchStartExit();
- mCalledActivityOptions = activityOptions;
+ mActivityTransitionState.startExitOutTransition(this, options);
}
if (mParent == null) {
Instrumentation.ActivityResult ar =
@@ -4559,13 +4546,10 @@ public class Activity extends ContextThemeWrapper
* to reverse its exit Transition. When the exit Transition completes,
* {@link #finish()} is called. If no entry Transition was used, finish() is called
* immediately and the Activity exit Transition is run.
- * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
- * android.app.ActivityOptions.ActivityTransitionListener)
+ * @see android.app.ActivityOptions#makeSceneTransitionAnimation(Activity, android.util.Pair[])
*/
public void finishWithTransition() {
- if (mEnterTransitionCoordinator != null) {
- mEnterTransitionCoordinator.startExit();
- } else {
+ if (!mActivityTransitionState.startExitBackTransition(this)) {
finish();
}
}
@@ -4643,6 +4627,27 @@ public class Activity extends ContextThemeWrapper
}
/**
+ * Called when an activity you launched with an activity transition exposes this
+ * Activity through a returning activity transition, giving you the resultCode
+ * and any additional data from it. This method will only be called if the activity
+ * set a result code other than {@link #RESULT_CANCELED} and it supports activity
+ * transitions with {@link Window#FEATURE_CONTENT_TRANSITIONS}.
+ *
+ * <p>The purpose of this function is to let the called Activity send a hint about
+ * its state so that this underlying Activity can prepare to be exposed. A call to
+ * this method does not guarantee that the called Activity has or will be exiting soon.
+ * It only indicates that it will expose this Activity's Window and it has
+ * some data to pass to prepare it.</p>
+ *
+ * @param resultCode The integer result code returned by the child activity
+ * through its setResult().
+ * @param data An Intent, which can return result data to the caller
+ * (various data can be attached to Intent "extras").
+ */
+ protected void onActivityReenter(int resultCode, Intent data) {
+ }
+
+ /**
* Create a new PendingIntent object which you can hand to others
* for them to use to send result data back to your
* {@link #onActivityResult} callback. The created object will be either
@@ -5246,7 +5251,8 @@ public class Activity extends ContextThemeWrapper
* This call has no effect on non-translucent activities or on activities with the
* {@link android.R.attr#windowIsFloating} attribute.
*
- * @see #convertToTranslucent(TranslucentConversionListener)
+ * @see #convertToTranslucent(android.app.Activity.TranslucentConversionListener,
+ * ActivityOptions)
* @see TranslucentConversionListener
*
* @hide
@@ -5544,18 +5550,18 @@ public class Activity extends ContextThemeWrapper
}
/**
- * When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
- * android.app.ActivityOptions.ActivityTransitionListener)} was used to start an Activity,
- * the Window will be triggered to enter with a Transition. <code>listener</code> allows
- * The Activity to listen to events of the entering transition and control the mapping of
- * shared elements. This requires {@link Window#FEATURE_CONTENT_TRANSITIONS}.
+ * When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity,
+ * android.view.View, String)} was used to start an Activity, <var>listener</var>
+ * will be called to handle shared elements. This requires
+ * {@link Window#FEATURE_CONTENT_TRANSITIONS}.
*
- * @param listener Used to listen to events in the entering transition.
+ * @param listener Used to manipulate how shared element transitions function.
*/
- public void setActivityTransitionListener(ActivityOptions.ActivityTransitionListener listener) {
- if (mEnterTransitionCoordinator != null) {
- mEnterTransitionCoordinator.setActivityTransitionListener(listener);
+ public void setSharedElementListener(SharedElementListener listener) {
+ if (listener == null) {
+ listener = new SharedElementListener();
}
+ mTransitionListener = listener;
}
// ------------------ Internal API ------------------
@@ -5621,19 +5627,23 @@ public class Activity extends ContextThemeWrapper
mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
com.android.internal.R.styleable.Window_windowNoDisplay, false);
mFragments.dispatchActivityCreated();
+ mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
}
final void performCreate(Bundle icicle) {
onCreate(icicle);
+ mActivityTransitionState.readState(icicle);
performCreateCommon();
}
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
onCreate(icicle, persistentState);
+ mActivityTransitionState.readState(icicle);
performCreateCommon();
}
final void performStart() {
+ mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
mFragments.noteStateNotSaved();
mCalled = false;
mFragments.execPendingActions();
@@ -5656,6 +5666,7 @@ public class Activity extends ContextThemeWrapper
lm.doReportStart();
}
}
+ mActivityTransitionState.enterReady(this);
}
final void performRestart() {
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 692efd7..a057c3e 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -17,18 +17,18 @@
package android.app;
import android.content.Context;
+import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.os.ResultReceiver;
-import android.transition.Transition;
-import android.util.ArrayMap;
import android.util.Pair;
import android.view.View;
import android.view.Window;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -108,6 +108,12 @@ public class ActivityOptions {
private static final String KEY_TRANSITION_COMPLETE_LISTENER
= "android:transitionCompleteListener";
+ private static final String KEY_TRANSITION_IS_RETURNING = "android:transitionIsReturning";
+ private static final String KEY_TRANSITION_SHARED_ELEMENTS = "android:sharedElementNames";
+ private static final String KEY_LOCAL_SHARED_ELEMENTS = "android:localSharedElementNames";
+ private static final String KEY_RESULT_DATA = "android:resultData";
+ private static final String KEY_RESULT_CODE = "android:resultCode";
+
/** @hide */
public static final int ANIM_NONE = 0;
/** @hide */
@@ -131,7 +137,12 @@ public class ActivityOptions {
private int mStartWidth;
private int mStartHeight;
private IRemoteCallback mAnimationStartedListener;
- private ResultReceiver mExitReceiver;
+ private ResultReceiver mTransitionReceiver;
+ private boolean mIsReturning;
+ private ArrayList<String> mSharedElementNames;
+ private ArrayList<String> mLocalSharedElementNames;
+ private Intent mResultData;
+ private int mResultCode;
/**
* Create an ActivityOptions specifying a custom animation to run when
@@ -334,7 +345,7 @@ public class ActivityOptions {
* <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be
* enabled on the calling Activity to cause an exit transition. The same must be in
* the called Activity to get an entering transition.</p>
- * @param window The window containing shared elements.
+ * @param activity The Activity whose window contains the shared elements.
* @param sharedElement The View to transition to the started Activity. sharedElement must
* have a non-null sharedElementName.
* @param sharedElementName The shared element name as used in the target Activity. This may
@@ -344,40 +355,70 @@ public class ActivityOptions {
* @see android.transition.Transition#setEpicenterCallback(
* android.transition.Transition.EpicenterCallback)
*/
- public static ActivityOptions makeSceneTransitionAnimation(Window window,
+ public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
View sharedElement, String sharedElementName) {
- return makeSceneTransitionAnimation(window,
- new SharedElementMappingListener(sharedElement, sharedElementName));
+ return makeSceneTransitionAnimation(activity, Pair.create(sharedElement, sharedElementName));
}
/**
* Create an ActivityOptions to transition between Activities using cross-Activity scene
* animations. This method carries the position of multiple shared elements to the started
- * Activity. The position of the first element in the value returned from
- * {@link android.app.ActivityOptions.ActivityTransitionListener#getSharedElementsMapping()}
+ * Activity. The position of the first element in sharedElements
* will be used as the epicenter for the exit Transition. The position of the associated
* shared element in the launched Activity will be the epicenter of its entering Transition.
*
* <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be
* enabled on the calling Activity to cause an exit transition. The same must be in
* the called Activity to get an entering transition.</p>
- * @param window The window containing shared elements.
- * @param listener The listener to use to monitor activity transition events.
+ * @param activity The Activity whose window contains the shared elements.
+ * @param sharedElements The names of the shared elements to transfer to the called
+ * Activity and their associated Views. The Views must each have
+ * a unique shared element name.
* @return Returns a new ActivityOptions object that you can use to
* supply these options as the options Bundle when starting an activity.
* Returns null if the Window does not have {@link Window#FEATURE_CONTENT_TRANSITIONS}.
* @see android.transition.Transition#setEpicenterCallback(
* android.transition.Transition.EpicenterCallback)
*/
- public static ActivityOptions makeSceneTransitionAnimation(Window window,
- ActivityTransitionListener listener) {
- if (!window.hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
+ public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
+ Pair<View, String>... sharedElements) {
+ if (!activity.getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
return null;
}
ActivityOptions opts = new ActivityOptions();
opts.mAnimationType = ANIM_SCENE_TRANSITION;
- ExitTransitionCoordinator exit = new ExitTransitionCoordinator(window, listener);
- opts.mExitReceiver = exit;
+
+ ArrayList<String> names = new ArrayList<String>();
+ ArrayList<String> mappedNames = new ArrayList<String>();
+
+ if (sharedElements != null) {
+ for (int i = 0; i < sharedElements.length; i++) {
+ Pair<View, String> sharedElement = sharedElements[i];
+ names.add(sharedElement.second);
+ mappedNames.add(sharedElement.first.getViewName());
+ }
+ }
+
+ ExitTransitionCoordinator exit = new ExitTransitionCoordinator(activity, names, names,
+ mappedNames, false);
+ opts.mTransitionReceiver = exit;
+ opts.mSharedElementNames = names;
+ opts.mLocalSharedElementNames = mappedNames;
+ opts.mIsReturning = false;
+ return opts;
+ }
+
+ /** @hide */
+ public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
+ ExitTransitionCoordinator exitCoordinator, ArrayList<String> sharedElementNames,
+ int resultCode, Intent resultData) {
+ ActivityOptions opts = new ActivityOptions();
+ opts.mAnimationType = ANIM_SCENE_TRANSITION;
+ opts.mSharedElementNames = sharedElementNames;
+ opts.mTransitionReceiver = exitCoordinator;
+ opts.mIsReturning = true;
+ opts.mResultCode = resultCode;
+ opts.mResultData = resultData;
return opts;
}
@@ -413,7 +454,12 @@ public class ActivityOptions {
break;
case ANIM_SCENE_TRANSITION:
- mExitReceiver = opts.getParcelable(KEY_TRANSITION_COMPLETE_LISTENER);
+ mTransitionReceiver = opts.getParcelable(KEY_TRANSITION_COMPLETE_LISTENER);
+ mIsReturning = opts.getBoolean(KEY_TRANSITION_IS_RETURNING, false);
+ mSharedElementNames = opts.getStringArrayList(KEY_TRANSITION_SHARED_ELEMENTS);
+ mLocalSharedElementNames = opts.getStringArrayList(KEY_LOCAL_SHARED_ELEMENTS);
+ mResultData = opts.getParcelable(KEY_RESULT_DATA);
+ mResultCode = opts.getInt(KEY_RESULT_CODE);
break;
}
}
@@ -470,15 +516,15 @@ public class ActivityOptions {
/** @hide */
public void dispatchActivityStopped() {
- if (mExitReceiver != null) {
- mExitReceiver.send(ActivityTransitionCoordinator.MSG_ACTIVITY_STOPPED, null);
+ if (mTransitionReceiver != null) {
+ mTransitionReceiver.send(ActivityTransitionCoordinator.MSG_ACTIVITY_STOPPED, null);
}
}
/** @hide */
public void dispatchStartExit() {
- if (mExitReceiver != null) {
- mExitReceiver.send(ActivityTransitionCoordinator.MSG_START_EXIT_TRANSITION, null);
+ if (mTransitionReceiver != null) {
+ mTransitionReceiver.send(ActivityTransitionCoordinator.MSG_START_EXIT_TRANSITION, null);
}
}
@@ -493,19 +539,37 @@ public class ActivityOptions {
}
/** @hide */
- public static void abort(Bundle options) {
- if (options != null) {
- (new ActivityOptions(options)).abort();
- }
+ public void setReturning() {
+ mIsReturning = true;
}
/** @hide */
- public EnterTransitionCoordinator createEnterActivityTransition(Activity activity) {
- EnterTransitionCoordinator coordinator = null;
- if (mAnimationType == ANIM_SCENE_TRANSITION) {
- coordinator = new EnterTransitionCoordinator(activity, mExitReceiver);
+ public boolean isReturning() {
+ return mIsReturning;
+ }
+
+ /** @hide */
+ public ArrayList<String> getSharedElementNames() {
+ return mSharedElementNames;
+ }
+
+ /** @hide */
+ public ArrayList<String> getLocalSharedElementNames() { return mLocalSharedElementNames; }
+
+ /** @hide */
+ public ResultReceiver getResultReceiver() { return mTransitionReceiver; }
+
+ /** @hide */
+ public int getResultCode() { return mResultCode; }
+
+ /** @hide */
+ public Intent getResultData() { return mResultData; }
+
+ /** @hide */
+ public static void abort(Bundle options) {
+ if (options != null) {
+ (new ActivityOptions(options)).abort();
}
- return coordinator;
}
/**
@@ -517,7 +581,12 @@ public class ActivityOptions {
if (otherOptions.mPackageName != null) {
mPackageName = otherOptions.mPackageName;
}
- mExitReceiver = null;
+ mTransitionReceiver = null;
+ mSharedElementNames = null;
+ mLocalSharedElementNames = null;
+ mIsReturning = false;
+ mResultData = null;
+ mResultCode = 0;
switch (otherOptions.mAnimationType) {
case ANIM_CUSTOM:
mAnimationType = otherOptions.mAnimationType;
@@ -562,9 +631,14 @@ public class ActivityOptions {
break;
case ANIM_SCENE_TRANSITION:
mAnimationType = otherOptions.mAnimationType;
- mExitReceiver = otherOptions.mExitReceiver;
+ mTransitionReceiver = otherOptions.mTransitionReceiver;
+ mSharedElementNames = otherOptions.mSharedElementNames;
+ mLocalSharedElementNames = otherOptions.mLocalSharedElementNames;
+ mIsReturning = otherOptions.mIsReturning;
mThumbnail = null;
mAnimationStartedListener = null;
+ mResultData = otherOptions.mResultData;
+ mResultCode = otherOptions.mResultCode;
break;
}
}
@@ -608,9 +682,14 @@ public class ActivityOptions {
break;
case ANIM_SCENE_TRANSITION:
b.putInt(KEY_ANIM_TYPE, mAnimationType);
- if (mExitReceiver != null) {
- b.putParcelable(KEY_TRANSITION_COMPLETE_LISTENER, mExitReceiver);
+ if (mTransitionReceiver != null) {
+ b.putParcelable(KEY_TRANSITION_COMPLETE_LISTENER, mTransitionReceiver);
}
+ b.putBoolean(KEY_TRANSITION_IS_RETURNING, mIsReturning);
+ b.putStringArrayList(KEY_TRANSITION_SHARED_ELEMENTS, mSharedElementNames);
+ b.putStringArrayList(KEY_LOCAL_SHARED_ELEMENTS, mLocalSharedElementNames);
+ b.putParcelable(KEY_RESULT_DATA, mResultData);
+ b.putInt(KEY_RESULT_CODE, mResultCode);
break;
}
return b;
@@ -630,126 +709,4 @@ public class ActivityOptions {
return null;
}
- /**
- * Listener provided in
- * {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
- * android.app.ActivityOptions.ActivityTransitionListener)} or in
- * {@link android.app.Activity#setActivityTransitionListener(
- * android.app.ActivityOptions.ActivityTransitionListener)} to monitor the Activity transitions.
- * The events can be used to customize or override Activity Transition behavior.
- */
- public static class ActivityTransitionListener {
- /**
- * Called when the enter Transition is ready to start, but hasn't started yet. If
- * {@link android.view.Window#getEnterTransition()} is non-null,
- * The entering views will be {@link View#INVISIBLE}.
- */
- public void onEnterReady() {}
-
- /**
- * Called when the remote exiting transition completes.
- */
- public void onRemoteExitComplete() {}
-
- /**
- * Called when the start state for shared elements is captured on enter.
- *
- * @param sharedElementNames The names of the shared elements that were accepted into
- * the View hierarchy.
- * @param sharedElements The shared elements that are part of the View hierarchy.
- * @param sharedElementSnapshots The Views containing snap shots of the shared element
- * from the launching Window. These elements will not
- * be part of the scene, but will be positioned relative
- * to the Window decor View.
- */
- public void onCaptureSharedElementStart(List<String> sharedElementNames,
- List<View> sharedElements, List<View> sharedElementSnapshots) {}
-
- /**
- * Called when the end state for shared elements is captured on enter.
- *
- * @param sharedElementNames The names of the shared elements that were accepted into
- * the View hierarchy.
- * @param sharedElements The shared elements that are part of the View hierarchy.
- * @param sharedElementSnapshots The Views containing snap shots of the shared element
- * from the launching Window. These elements will not
- * be part of the scene, but will be positioned relative
- * to the Window decor View.
- */
- public void onCaptureSharedElementEnd(List<String> sharedElementNames,
- List<View> sharedElements, List<View> sharedElementSnapshots) {}
-
- /**
- * Called when the enter Transition has been started.
- * @param sharedElementNames The names of shared elements that were transferred.
- * @param sharedElements The shared elements that were transferred.
- */
- public void onStartEnterTransition(List<String> sharedElementNames,
- List<View> sharedElements) {}
-
- /**
- * Called when the exit Transition has been started.
- * @param sharedElementNames The names of all shared elements that will be transferred.
- * @param sharedElements All shared elements that will be transferred.
- */
- public void onStartExitTransition(List<String> sharedElementNames,
- List<View> sharedElements) {}
-
- /**
- * Called when the exiting shared element transition completes.
- */
- public void onSharedElementExitTransitionComplete() {}
-
- /**
- * Called on exit when the shared element has been transferred.
- * @param sharedElementNames The names of all shared elements that were transferred.
- * @param sharedElements All shared elements that will were transferred.
- */
- public void onSharedElementTransferred(List<String> sharedElementNames,
- List<View> sharedElements) {}
-
- /**
- * Called when the exit transition has completed.
- */
- public void onExitTransitionComplete() {}
-
- /**
- * Returns a mapping from a View in the View hierarchy to the shared element name used
- * in the call. This is called twice -- once when the view is
- * entering and again when it exits. A null return value indicates that the
- * View hierachy can be trusted without any remapping.
- * @return A map from a View in the hierarchy to the shared element name used in the
- * call.
- */
- public Pair<View, String>[] getSharedElementsMapping() { return null; }
-
- /**
- * Returns <code>true</code> if the ActivityTransitionListener will handle removing
- * rejected shared elements from the scene. If <code>false</code> is returned, a default
- * animation will be used to remove the rejected shared elements from the scene.
- *
- * @param rejectedSharedElements Views containing visual information of shared elements
- * that are not part of the entering scene. These Views
- * are positioned relative to the Window decor View.
- * @return <code>false</code> if the default animation should be used to remove the
- * rejected shared elements from the scene or <code>true</code> if the listener provides
- * custom handling.
- */
- public boolean handleRejectedSharedElements(List<View> rejectedSharedElements) {
- return false;
- }
- }
-
- private static class SharedElementMappingListener extends ActivityTransitionListener {
- Pair<View, String>[] mSharedElementsMapping = new Pair[1];
-
- public SharedElementMappingListener(View view, String name) {
- mSharedElementsMapping[0] = Pair.create(view, name);
- }
-
- @Override
- public Pair<View, String>[] getSharedElementsMapping() {
- return mSharedElementsMapping;
- }
- }
}
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index ca64788..6c6a52f 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -15,27 +15,14 @@
*/
package android.app;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
import android.graphics.Rect;
-import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
import android.transition.Transition;
-import android.transition.TransitionManager;
import android.transition.TransitionSet;
import android.util.ArrayMap;
-import android.util.Pair;
-import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewGroupOverlay;
-import android.view.ViewTreeObserver;
import android.view.Window;
import android.widget.ImageView;
@@ -83,14 +70,13 @@ import java.util.Collection;
* - onActivityStopped() is called and all exited Views are made VISIBLE.
*
* Typical finishWithTransition goes like this:
- * 1) finishWithTransition() calls startExit()
- * - The Window start transitioning to Translucent
+ * 1) finishWithTransition() creates an ExitTransitionCoordinator and calls startExit()
+ * - The Window start transitioning to Translucent with a new ActivityOptions.
* - If no background exists, a black background is substituted
- * - MSG_PREPARE_RESTORE is sent to the ExitTransitionCoordinator
* - The shared elements in the scene are matched against those shared elements
* that were sent by comparing the names.
* - The exit transition is started by setting Views to INVISIBLE.
- * 2) MSG_PREPARE_RESTORE is received by the EnterTransitionCoordinator
+ * 2) The ActivityOptions is received by the Activity and an EnterTransitionCoordinator is created.
* - All transitioning views are made VISIBLE to reverse what was done when onActivityStopped()
* was called
* 3) The Window is made translucent and a callback is received
@@ -98,21 +84,21 @@ import java.util.Collection;
* 4) The background alpha animation completes
* 5) The shared element transition completes
* - After both 4 & 5 complete, MSG_TAKE_SHARED_ELEMENTS is sent to the
- * ExitTransitionCoordinator
- * 6) MSG_TAKE_SHARED_ELEMENTS is received by ExitTransitionCoordinator
+ * EnterTransitionCoordinator
+ * 6) MSG_TAKE_SHARED_ELEMENTS is received by EnterTransitionCoordinator
* - Shared elements are made VISIBLE
* - Shared elements positions and size are set to match the end state of the calling
* Activity.
* - The shared element transition is started
* - If the window allows overlapping transitions, the views transition is started by setting
* the entering Views to VISIBLE.
- * - MSG_HIDE_SHARED_ELEMENTS is sent to the EnterTransitionCoordinator
- * 7) MSG_HIDE_SHARED_ELEMENTS is received by the EnterTransitionCoordinator
+ * - MSG_HIDE_SHARED_ELEMENTS is sent to the ExitTransitionCoordinator
+ * 7) MSG_HIDE_SHARED_ELEMENTS is received by the ExitTransitionCoordinator
* - The shared elements are made INVISIBLE
* 8) The exit transition completes in the finishing Activity.
- * - MSG_EXIT_TRANSITION_COMPLETE is sent to the ExitTransitionCoordinator.
+ * - MSG_EXIT_TRANSITION_COMPLETE is sent to the EnterTransitionCoordinator.
* - finish() is called on the exiting Activity
- * 9) The MSG_EXIT_TRANSITION_COMPLETE is received by the ExitTransitionCoordinator.
+ * 9) The MSG_EXIT_TRANSITION_COMPLETE is received by the EnterTransitionCoordinator.
* - If the window doesn't allow overlapping enter transitions, the enter transition is started
* by setting entering views to VISIBLE.
*/
@@ -120,30 +106,24 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
private static final String TAG = "ActivityTransitionCoordinator";
/**
- * The names of shared elements that are transitioned to the started Activity.
- * This is also the name of shared elements that the started Activity accepted.
- */
- public static final String KEY_SHARED_ELEMENT_NAMES = "android:shared_element_names";
-
- public static final String KEY_SHARED_ELEMENT_STATE = "android:shared_element_state";
-
- /**
* For Activity transitions, the called Activity's listener to receive calls
* when transitions complete.
*/
- static final String KEY_TRANSITION_RESULTS_RECEIVER = "android:transitionTargetListener";
+ static final String KEY_REMOTE_RECEIVER = "android:remoteReceiver";
+
+ protected static final String KEY_SCREEN_X = "shared_element:screenX";
+ protected static final String KEY_SCREEN_Y = "shared_element:screenY";
+ protected static final String KEY_TRANSLATION_Z = "shared_element:translationZ";
+ protected static final String KEY_WIDTH = "shared_element:width";
+ protected static final String KEY_HEIGHT = "shared_element:height";
+ protected static final String KEY_BITMAP = "shared_element:bitmap";
+ protected static final String KEY_SCALE_TYPE = "shared_element:scaleType";
+ protected static final String KEY_IMAGE_MATRIX = "shared_element:imageMatrix";
- private static final String KEY_SCREEN_X = "shared_element:screenX";
- private static final String KEY_SCREEN_Y = "shared_element:screenY";
- private static final String KEY_TRANSLATION_Z = "shared_element:translationZ";
- private static final String KEY_WIDTH = "shared_element:width";
- private static final String KEY_HEIGHT = "shared_element:height";
- private static final String KEY_NAME = "shared_element:name";
- private static final String KEY_BITMAP = "shared_element:bitmap";
- private static final String KEY_SCALE_TYPE = "shared_element:scaleType";
- private static final String KEY_IMAGE_MATRIX = "shared_element:imageMatrix";
+ // The background fade in/out duration. 150ms is pretty quick, but not abrupt.
+ public static final int FADE_BACKGROUND_DURATION_MS = 150;
- private static final ImageView.ScaleType[] SCALE_TYPE_VALUES = ImageView.ScaleType.values();
+ protected static final ImageView.ScaleType[] SCALE_TYPE_VALUES = ImageView.ScaleType.values();
/**
* Sent by the exiting coordinator (either EnterTransitionCoordinator
@@ -154,7 +134,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
* until this message is received, but may wait for
* MSG_EXIT_TRANSITION_COMPLETE if allowOverlappingTransitions() is true.
*/
- public static final int MSG_SET_LISTENER = 100;
+ public static final int MSG_SET_REMOTE_RECEIVER = 100;
/**
* Sent by the entering coordinator to tell the exiting coordinator
@@ -165,17 +145,10 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
public static final int MSG_HIDE_SHARED_ELEMENTS = 101;
/**
- * Sent by the EnterTransitionCoordinator to tell the
- * ExitTransitionCoordinator to hide all of its exited views after
- * MSG_ACTIVITY_STOPPED has caused them all to show.
- */
- public static final int MSG_PREPARE_RESTORE = 102;
-
- /**
* Sent by the exiting Activity in ActivityOptions#dispatchActivityStopped
* to leave the Activity in a good state after it has been hidden.
*/
- public static final int MSG_ACTIVITY_STOPPED = 103;
+ public static final int MSG_ACTIVITY_STOPPED = 102;
/**
* Sent by the exiting coordinator (either EnterTransitionCoordinator
@@ -186,7 +159,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
* until this message is received, but may wait for
* MSG_EXIT_TRANSITION_COMPLETE if allowOverlappingTransitions() is true.
*/
- public static final int MSG_TAKE_SHARED_ELEMENTS = 104;
+ public static final int MSG_TAKE_SHARED_ELEMENTS = 103;
/**
* Sent by the exiting coordinator (either
@@ -196,309 +169,41 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
* remote coordinator. If it is false, it will trigger the enter
* transition to start.
*/
- public static final int MSG_EXIT_TRANSITION_COMPLETE = 105;
+ public static final int MSG_EXIT_TRANSITION_COMPLETE = 104;
/**
* Sent by Activity#startActivity to begin the exit transition.
*/
- public static final int MSG_START_EXIT_TRANSITION = 106;
-
- private Window mWindow;
- private ArrayList<View> mSharedElements = new ArrayList<View>();
- private ArrayList<String> mTargetSharedNames = new ArrayList<String>();
- private ActivityOptions.ActivityTransitionListener mListener =
- new ActivityOptions.ActivityTransitionListener();
- private ArrayList<View> mEnteringViews;
- private ResultReceiver mRemoteResultReceiver;
- private boolean mNotifiedSharedElementTransitionComplete;
- private boolean mNotifiedExitTransitionComplete;
- private boolean mSharedElementTransitionStarted;
-
- private FixedEpicenterCallback mEpicenterCallback = new FixedEpicenterCallback();
-
- private Transition.TransitionListener mSharedElementListener =
- new Transition.TransitionListenerAdapter() {
- @Override
- public void onTransitionEnd(Transition transition) {
- transition.removeListener(this);
- onSharedElementTransitionEnd();
- }
- };
-
- private Transition.TransitionListener mExitListener =
- new Transition.TransitionListenerAdapter() {
- @Override
- public void onTransitionEnd(Transition transition) {
- transition.removeListener(this);
- onExitTransitionEnd();
- }
- };
-
- public ActivityTransitionCoordinator(Window window)
- {
- super(new Handler());
- mWindow = window;
- }
-
- // -------------------- ResultsReceiver Overrides ----------------------
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- switch (resultCode) {
- case MSG_SET_LISTENER:
- ResultReceiver resultReceiver
- = resultData.getParcelable(KEY_TRANSITION_RESULTS_RECEIVER);
- setRemoteResultReceiver(resultReceiver);
- onSetResultReceiver();
- break;
- case MSG_HIDE_SHARED_ELEMENTS:
- onHideSharedElements();
- break;
- case MSG_PREPARE_RESTORE:
- onPrepareRestore();
- break;
- case MSG_EXIT_TRANSITION_COMPLETE:
- if (!mSharedElementTransitionStarted) {
- send(resultCode, resultData);
- } else {
- onRemoteSceneExitComplete();
- }
- break;
- case MSG_TAKE_SHARED_ELEMENTS:
- ArrayList<String> sharedElementNames
- = resultData.getStringArrayList(KEY_SHARED_ELEMENT_NAMES);
- Bundle sharedElementState = resultData.getBundle(KEY_SHARED_ELEMENT_STATE);
- onTakeSharedElements(sharedElementNames, sharedElementState);
- break;
- case MSG_ACTIVITY_STOPPED:
- onActivityStopped();
- break;
- case MSG_START_EXIT_TRANSITION:
- startExit();
- break;
- }
- }
-
- // -------------------- calls that can be overridden by subclasses --------------------
-
- /**
- * Called when MSG_SET_LISTENER is received. This will only be received by
- * ExitTransitionCoordinator.
- */
- protected void onSetResultReceiver() {}
-
- /**
- * Called when MSG_HIDE_SHARED_ELEMENTS is received
- */
- protected void onHideSharedElements() {
- setViewVisibility(getSharedElements(), View.INVISIBLE);
- mListener.onSharedElementTransferred(getSharedElementNames(), getSharedElements());
- }
-
- /**
- * Called when MSG_PREPARE_RESTORE is called. This will only be received by
- * ExitTransitionCoordinator.
- */
- protected void onPrepareRestore() {
- mListener.onEnterReady();
- }
-
- /**
- * Called when MSG_EXIT_TRANSITION_COMPLETE is received -- the remote coordinator has
- * completed its exit transition. This can be called by the ExitTransitionCoordinator when
- * starting an Activity or EnterTransitionCoordinator when called with finishWithTransition.
- */
- protected void onRemoteSceneExitComplete() {
- if (!allowOverlappingTransitions()) {
- Transition transition = beginTransition(mEnteringViews, false, true, true);
- onStartEnterTransition(transition, mEnteringViews);
- }
- mListener.onRemoteExitComplete();
- }
-
- /**
- * Called when MSG_TAKE_SHARED_ELEMENTS is received. This means that the shared elements are
- * in a stable state and ready to move to the Window.
- * @param sharedElementNames The names of the shared elements to move.
- * @param state Contains the shared element states (size & position)
- */
- protected void onTakeSharedElements(ArrayList<String> sharedElementNames, Bundle state) {
- setSharedElements();
- reconcileSharedElements(sharedElementNames);
- mEnteringViews.removeAll(mSharedElements);
- final ArrayList<View> accepted = new ArrayList<View>();
- final ArrayList<View> rejected = new ArrayList<View>();
- createSharedElementImages(accepted, rejected, sharedElementNames, state);
- ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageViewState =
- setSharedElementState(state, accepted);
- handleRejected(rejected);
-
- if (getViewsTransition() != null) {
- setViewVisibility(mEnteringViews, View.INVISIBLE);
- }
- setViewVisibility(mSharedElements, View.VISIBLE);
- Transition transition = beginTransition(mEnteringViews, true, allowOverlappingTransitions(),
- true);
- setOriginalImageViewState(originalImageViewState);
-
- if (allowOverlappingTransitions()) {
- onStartEnterTransition(transition, mEnteringViews);
- }
-
- mRemoteResultReceiver.send(MSG_HIDE_SHARED_ELEMENTS, null);
- }
+ public static final int MSG_START_EXIT_TRANSITION = 105;
/**
- * Called when MSG_ACTIVITY_STOPPED is received. This is received when Activity.onStop is
- * called after running startActivity* is called using an Activity Transition.
+ * It took too long for a message from the entering Activity, so we canceled the transition.
*/
- protected void onActivityStopped() {}
-
- /**
- * Called when the start transition is ready to run. This may be immediately after
- * MSG_TAKE_SHARED_ELEMENTS or MSG_EXIT_TRANSITION_COMPLETE, depending on whether
- * overlapping transitions are allowed.
- * @param transition The transition currently started.
- * @param enteringViews The views entering the scene. This won't include shared elements.
- */
- protected void onStartEnterTransition(Transition transition, ArrayList<View> enteringViews) {
+ public static final int MSG_CANCEL = 106;
+
+ final private Window mWindow;
+ final protected ArrayList<String> mAllSharedElementNames;
+ final protected ArrayList<View> mSharedElements = new ArrayList<View>();
+ final protected ArrayList<String> mSharedElementNames = new ArrayList<String>();
+ final protected ArrayList<View> mTransitioningViews = new ArrayList<View>();
+ final protected SharedElementListener mListener;
+ protected ResultReceiver mResultReceiver;
+ final private FixedEpicenterCallback mEpicenterCallback = new FixedEpicenterCallback();
+
+ public ActivityTransitionCoordinator(Window window,
+ ArrayList<String> allSharedElementNames,
+ ArrayList<String> accepted, ArrayList<String> localNames,
+ SharedElementListener listener) {
+ super(new Handler());
+ mWindow = window;
+ mListener = listener;
+ mAllSharedElementNames = allSharedElementNames;
+ setSharedElements(accepted, localNames);
if (getViewsTransition() != null) {
- setViewVisibility(enteringViews, View.VISIBLE);
+ getDecor().captureTransitioningViews(mTransitioningViews);
+ mTransitioningViews.removeAll(mSharedElements);
}
- mEnteringViews = null;
- mListener.onStartEnterTransition(getSharedElementNames(), getSharedElements());
- }
-
- /**
- * Called when the exit transition has started.
- * @param exitingViews The views leaving the scene. This won't include shared elements.
- */
- protected void onStartExitTransition(ArrayList<View> exitingViews) {}
-
- /**
- * Called during the exit when the shared element transition has completed.
- */
- protected void onSharedElementTransitionEnd() {
- Bundle bundle = new Bundle();
- int[] tempLoc = new int[2];
- for (int i = 0; i < mSharedElements.size(); i++) {
- View sharedElement = mSharedElements.get(i);
- String name = mTargetSharedNames.get(i);
- captureSharedElementState(sharedElement, name, bundle, tempLoc);
- }
- Bundle allValues = new Bundle();
- allValues.putStringArrayList(KEY_SHARED_ELEMENT_NAMES, getSharedElementNames());
- allValues.putBundle(KEY_SHARED_ELEMENT_STATE, bundle);
- sharedElementTransitionComplete(allValues);
- mListener.onSharedElementExitTransitionComplete();
- }
-
- /**
- * Called after the shared element transition is complete to pass the shared element state
- * to the remote coordinator.
- * @param bundle The Bundle to send to the coordinator containing the shared element state.
- */
- protected abstract void sharedElementTransitionComplete(Bundle bundle);
-
- /**
- * Called when the exit transition finishes.
- */
- protected void onExitTransitionEnd() {
- mListener.onExitTransitionComplete();
- }
-
- /**
- * Called to start the exit transition. Launched from ActivityOptions#dispatchStartExit
- */
- protected abstract void startExit();
-
- /**
- * A non-null transition indicates that the Views of the Window should be made INVISIBLE.
- * @return The Transition used to cause transitioning views to either enter or exit the scene.
- */
- protected abstract Transition getViewsTransition();
-
- /**
- * @return The Transition used to move the shared elements from the start position and size
- * to the end position and size.
- */
- protected abstract Transition getSharedElementTransition();
-
- /**
- * @return When the enter transition should overlap with the exit transition of the
- * remote controller.
- */
- protected abstract boolean allowOverlappingTransitions();
-
- // called by subclasses
-
- protected void notifySharedElementTransitionComplete(Bundle sharedElements) {
- if (!mNotifiedSharedElementTransitionComplete) {
- mNotifiedSharedElementTransitionComplete = true;
- mRemoteResultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, sharedElements);
- }
- }
-
- protected void notifyExitTransitionComplete() {
- if (!mNotifiedExitTransitionComplete) {
- mNotifiedExitTransitionComplete = true;
- mRemoteResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null);
- }
- }
-
- protected void notifyPrepareRestore() {
- mRemoteResultReceiver.send(MSG_PREPARE_RESTORE, null);
- }
-
- protected void setRemoteResultReceiver(ResultReceiver resultReceiver) {
- mRemoteResultReceiver = resultReceiver;
- }
-
- protected void notifySetListener() {
- Bundle bundle = new Bundle();
- bundle.putParcelable(KEY_TRANSITION_RESULTS_RECEIVER, this);
- mRemoteResultReceiver.send(MSG_SET_LISTENER, bundle);
- }
-
- protected void setEnteringViews(ArrayList<View> views) {
- mEnteringViews = views;
- }
-
- protected void setSharedElements() {
- Pair<View, String>[] sharedElements = mListener.getSharedElementsMapping();
- mSharedElements.clear();
- mTargetSharedNames.clear();
- if (sharedElements == null) {
- ArrayMap<String, View> map = new ArrayMap<String, View>();
- if (getViewsTransition() != null) {
- setViewVisibility(mEnteringViews, View.VISIBLE);
- }
- getDecor().findNamedViews(map);
- if (getViewsTransition() != null) {
- setViewVisibility(mEnteringViews, View.INVISIBLE);
- }
- for (int i = 0; i < map.size(); i++) {
- View view = map.valueAt(i);
- String name = map.keyAt(i);
- mSharedElements.add(view);
- mTargetSharedNames.add(name);
- }
- } else {
- for (int i = 0; i < sharedElements.length; i++) {
- Pair<View, String> viewStringPair = sharedElements[i];
- View view = viewStringPair.first;
- String name = viewStringPair.second;
- mSharedElements.add(view);
- mTargetSharedNames.add(name);
- }
- }
- }
-
- protected ArrayList<View> getSharedElements() {
- return mSharedElements;
- }
-
- protected ArrayList<String> getSharedElementNames() {
- return mTargetSharedNames;
+ setEpicenter();
}
protected Window getWindow() {
@@ -509,238 +214,43 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
return (mWindow == null) ? null : (ViewGroup) mWindow.getDecorView();
}
- protected void startExitTransition(ArrayList<String> sharedElements) {
- setSharedElements();
- reconcileSharedElements(sharedElements);
- ArrayList<View> transitioningViews = captureTransitioningViews();
- beginTransition(transitioningViews, true, true, false);
- onStartExitTransition(transitioningViews);
- if (getViewsTransition() != null) {
- setViewVisibility(transitioningViews, View.INVISIBLE);
+ /**
+ * Sets the transition epicenter to the position of the first shared element.
+ */
+ protected void setEpicenter() {
+ View epicenter = null;
+ if (!mAllSharedElementNames.isEmpty() && !mSharedElementNames.isEmpty() &&
+ mAllSharedElementNames.get(0).equals(mSharedElementNames.get(0))) {
+ epicenter = mSharedElements.get(0);
}
- mListener.onStartExitTransition(getSharedElementNames(), getSharedElements());
- }
-
- protected void clearConnections() {
- mRemoteResultReceiver = null;
+ setEpicenter(epicenter);
}
- // public API
-
- public void setActivityTransitionListener(ActivityOptions.ActivityTransitionListener listener) {
- if (listener == null) {
- mListener = new ActivityOptions.ActivityTransitionListener();
+ private void setEpicenter(View view) {
+ if (view == null) {
+ mEpicenterCallback.setEpicenter(null);
} else {
- mListener = listener;
+ int[] loc = new int[2];
+ view.getLocationOnScreen(loc);
+ int left = loc[0] + Math.round(view.getTranslationX());
+ int top = loc[1] + Math.round(view.getTranslationY());
+ int right = left + view.getWidth();
+ int bottom = top + view.getHeight();
+ Rect epicenter = new Rect(left, top, right, bottom);
+ mEpicenterCallback.setEpicenter(epicenter);
}
}
- // private methods
-
- private Transition configureTransition(Transition transition) {
- if (transition != null) {
- transition = transition.clone();
- transition.setEpicenterCallback(mEpicenterCallback);
- }
- return transition;
- }
-
- private void reconcileSharedElements(ArrayList<String> sharedElementNames) {
- // keep only those that are in sharedElementNames.
- int numSharedElements = sharedElementNames.size();
- int targetIndex = 0;
- for (int i = 0; i < numSharedElements; i++) {
- String name = sharedElementNames.get(i);
- int index = mTargetSharedNames.indexOf(name);
- if (index >= 0) {
- // Swap the items at the indexes if necessary.
- if (index != targetIndex) {
- View temp = mSharedElements.get(index);
- mSharedElements.set(index, mSharedElements.get(targetIndex));
- mSharedElements.set(targetIndex, temp);
- mTargetSharedNames.set(index, mTargetSharedNames.get(targetIndex));
- mTargetSharedNames.set(targetIndex, name);
- }
- targetIndex++;
- }
- }
- for (int i = mSharedElements.size() - 1; i >= targetIndex; i--) {
- mSharedElements.remove(i);
- mTargetSharedNames.remove(i);
- }
- Rect epicenter = null;
- if (!mTargetSharedNames.isEmpty()
- && mTargetSharedNames.get(0).equals(sharedElementNames.get(0))) {
- epicenter = calcEpicenter(mSharedElements.get(0));
- }
- mEpicenterCallback.setEpicenter(epicenter);
- }
-
- private ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> setSharedElementState(
- Bundle sharedElementState, final ArrayList<View> acceptedOverlayViews) {
- ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageState =
- new ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>>();
- final int[] tempLoc = new int[2];
- if (sharedElementState != null) {
- for (int i = 0; i < mSharedElements.size(); i++) {
- View sharedElement = mSharedElements.get(i);
- String name = mTargetSharedNames.get(i);
- Pair<ImageView.ScaleType, Matrix> originalState = getOldImageState(sharedElement,
- name, sharedElementState);
- if (originalState != null) {
- originalImageState.put((ImageView) sharedElement, originalState);
- }
- View parent = (View) sharedElement.getParent();
- parent.getLocationOnScreen(tempLoc);
- setSharedElementState(sharedElement, name, sharedElementState, tempLoc);
- sharedElement.requestLayout();
- }
- }
- mListener.onCaptureSharedElementStart(mTargetSharedNames, mSharedElements,
- acceptedOverlayViews);
-
- getDecor().getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
- mListener.onCaptureSharedElementEnd(mTargetSharedNames, mSharedElements,
- acceptedOverlayViews);
- mSharedElementTransitionStarted = true;
- return true;
- }
- }
- );
- return originalImageState;
- }
-
- private static Pair<ImageView.ScaleType, Matrix> getOldImageState(View view, String name,
- Bundle transitionArgs) {
- if (!(view instanceof ImageView)) {
- return null;
- }
- Bundle bundle = transitionArgs.getBundle(name);
- int scaleTypeInt = bundle.getInt(KEY_SCALE_TYPE, -1);
- if (scaleTypeInt < 0) {
- return null;
- }
-
- ImageView imageView = (ImageView) view;
- ImageView.ScaleType originalScaleType = imageView.getScaleType();
-
- Matrix originalMatrix = null;
- if (originalScaleType == ImageView.ScaleType.MATRIX) {
- originalMatrix = new Matrix(imageView.getImageMatrix());
- }
-
- return Pair.create(originalScaleType, originalMatrix);
- }
-
- /**
- * Sets the captured values from a previous
- * {@link #captureSharedElementState(android.view.View, String, android.os.Bundle, int[])}
- * @param view The View to apply placement changes to.
- * @param name The shared element name given from the source Activity.
- * @param transitionArgs A <code>Bundle</code> containing all placementinformation for named
- * shared elements in the scene.
- * @param parentLoc The x and y coordinates of the parent's screen position.
- */
- private static void setSharedElementState(View view, String name, Bundle transitionArgs,
- int[] parentLoc) {
- Bundle sharedElementBundle = transitionArgs.getBundle(name);
- if (sharedElementBundle == null) {
- return;
- }
-
- if (view instanceof ImageView) {
- int scaleTypeInt = sharedElementBundle.getInt(KEY_SCALE_TYPE, -1);
- if (scaleTypeInt >= 0) {
- ImageView imageView = (ImageView) view;
- ImageView.ScaleType scaleType = SCALE_TYPE_VALUES[scaleTypeInt];
- imageView.setScaleType(scaleType);
- if (scaleType == ImageView.ScaleType.MATRIX) {
- float[] matrixValues = sharedElementBundle.getFloatArray(KEY_IMAGE_MATRIX);
- Matrix matrix = new Matrix();
- matrix.setValues(matrixValues);
- imageView.setImageMatrix(matrix);
- }
- }
- }
-
- float z = sharedElementBundle.getFloat(KEY_TRANSLATION_Z);
- view.setTranslationZ(z);
-
- int x = sharedElementBundle.getInt(KEY_SCREEN_X);
- int y = sharedElementBundle.getInt(KEY_SCREEN_Y);
- int width = sharedElementBundle.getInt(KEY_WIDTH);
- int height = sharedElementBundle.getInt(KEY_HEIGHT);
-
- int widthSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
- int heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
- view.measure(widthSpec, heightSpec);
-
- int left = x - parentLoc[0];
- int top = y - parentLoc[1];
- int right = left + width;
- int bottom = top + height;
- view.layout(left, top, right, bottom);
+ public ArrayList<String> getAcceptedNames() {
+ return mSharedElementNames;
}
- /**
- * Captures placement information for Views with a shared element name for
- * Activity Transitions.
- * @param view The View to capture the placement information for.
- * @param name The shared element name in the target Activity to apply the placement
- * information for.
- * @param transitionArgs Bundle to store shared element placement information.
- * @param tempLoc A temporary int[2] for capturing the current location of views.
- * @see #setSharedElementState(android.view.View, String, android.os.Bundle, int[])
- */
- private static void captureSharedElementState(View view, String name, Bundle transitionArgs,
- int[] tempLoc) {
- Bundle sharedElementBundle = new Bundle();
- view.getLocationOnScreen(tempLoc);
- float scaleX = view.getScaleX();
- sharedElementBundle.putInt(KEY_SCREEN_X, tempLoc[0]);
- int width = Math.round(view.getWidth() * scaleX);
- sharedElementBundle.putInt(KEY_WIDTH, width);
-
- float scaleY = view.getScaleY();
- sharedElementBundle.putInt(KEY_SCREEN_Y, tempLoc[1]);
- int height= Math.round(view.getHeight() * scaleY);
- sharedElementBundle.putInt(KEY_HEIGHT, height);
-
- sharedElementBundle.putFloat(KEY_TRANSLATION_Z, view.getTranslationZ());
-
- sharedElementBundle.putString(KEY_NAME, view.getViewName());
-
- Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- view.draw(canvas);
- sharedElementBundle.putParcelable(KEY_BITMAP, bitmap);
-
- if (view instanceof ImageView) {
- ImageView imageView = (ImageView) view;
- int scaleTypeInt = scaleTypeToInt(imageView.getScaleType());
- sharedElementBundle.putInt(KEY_SCALE_TYPE, scaleTypeInt);
- if (imageView.getScaleType() == ImageView.ScaleType.MATRIX) {
- float[] matrix = new float[9];
- imageView.getImageMatrix().getValues(matrix);
- sharedElementBundle.putFloatArray(KEY_IMAGE_MATRIX, matrix);
- }
+ public ArrayList<String> getMappedNames() {
+ ArrayList<String> names = new ArrayList<String>(mSharedElements.size());
+ for (int i = 0; i < mSharedElements.size(); i++) {
+ names.add(mSharedElements.get(i).getViewName());
}
-
- transitionArgs.putBundle(name, sharedElementBundle);
- }
-
- private static Rect calcEpicenter(View view) {
- int[] loc = new int[2];
- view.getLocationOnScreen(loc);
- int left = loc[0] + Math.round(view.getTranslationX());
- int top = loc[1] + Math.round(view.getTranslationY());
- int right = left + view.getWidth();
- int bottom = top + view.getHeight();
- return new Rect(left, top, right, bottom);
+ return names;
}
public static void setViewVisibility(Collection<View> views, int visibility) {
@@ -751,12 +261,12 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
}
}
- private static Transition addTransitionTargets(Transition transition, Collection<View> views) {
+ protected static Transition addTargets(Transition transition, Collection<View> views) {
if (transition == null || views == null || views.isEmpty()) {
return null;
}
TransitionSet set = new TransitionSet();
- set.addTransition(transition.clone());
+ set.addTransition(transition);
if (views != null) {
for (View view: views) {
set.addTarget(view);
@@ -765,152 +275,62 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
return set;
}
- private ArrayList<View> captureTransitioningViews() {
- if (getViewsTransition() == null) {
- return null;
- }
- ArrayList<View> transitioningViews = new ArrayList<View>();
- getDecor().captureTransitioningViews(transitioningViews);
- transitioningViews.removeAll(getSharedElements());
- return transitioningViews;
- }
-
- private Transition getSharedElementTransition(boolean isEnter) {
- Transition transition = getSharedElementTransition();
- if (transition == null) {
- return null;
- }
- transition = configureTransition(transition);
- if (!isEnter) {
- transition.addListener(mSharedElementListener);
- }
- return transition;
- }
-
- private Transition getViewsTransition(ArrayList<View> transitioningViews, boolean isEnter) {
- Transition transition = getViewsTransition();
- if (transition == null) {
- return null;
- }
- transition = configureTransition(transition);
- if (!isEnter) {
- transition.addListener(mExitListener);
- }
- return addTransitionTargets(transition, transitioningViews);
- }
-
- private Transition beginTransition(ArrayList<View> transitioningViews,
- boolean transitionSharedElement, boolean transitionViews, boolean isEnter) {
- Transition sharedElementTransition = null;
- if (transitionSharedElement) {
- sharedElementTransition = getSharedElementTransition(isEnter);
- if (!isEnter && sharedElementTransition == null) {
- onSharedElementTransitionEnd();
- }
- }
- Transition viewsTransition = null;
- if (transitionViews) {
- viewsTransition = getViewsTransition(transitioningViews, isEnter);
- if (!isEnter && viewsTransition == null) {
- onExitTransitionEnd();
- }
- }
-
- Transition transition = null;
- if (sharedElementTransition == null) {
- transition = viewsTransition;
- } else if (viewsTransition == null) {
- transition = sharedElementTransition;
- } else {
- TransitionSet set = new TransitionSet();
- set.addTransition(sharedElementTransition);
- set.addTransition(viewsTransition);
- transition = set;
- }
+ protected Transition configureTransition(Transition transition) {
if (transition != null) {
- TransitionManager.beginDelayedTransition(getDecor(), transition);
- if (transitionSharedElement && !mSharedElements.isEmpty()) {
- mSharedElements.get(0).invalidate();
- } else if (transitionViews && !transitioningViews.isEmpty()) {
- transitioningViews.get(0).invalidate();
- }
+ transition = transition.clone();
+ transition.setEpicenterCallback(mEpicenterCallback);
}
return transition;
}
- private void handleRejected(final ArrayList<View> rejected) {
- int numRejected = rejected.size();
- if (numRejected == 0) {
- return;
- }
- boolean rejectionHandled = mListener.handleRejectedSharedElements(rejected);
- if (rejectionHandled) {
- return;
- }
-
- ViewGroupOverlay overlay = getDecor().getOverlay();
- ObjectAnimator animator = null;
- for (int i = 0; i < numRejected; i++) {
- View view = rejected.get(i);
- overlay.add(view);
- animator = ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0);
- animator.start();
- }
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- ViewGroupOverlay overlay = getDecor().getOverlay();
- for (int i = rejected.size() - 1; i >= 0; i--) {
- overlay.remove(rejected.get(i));
+ protected static Transition mergeTransitions(Transition transition1, Transition transition2) {
+ if (transition1 == null) {
+ return transition2;
+ } else if (transition2 == null) {
+ return transition1;
+ } else {
+ TransitionSet transitionSet = new TransitionSet();
+ transitionSet.addTransition(transition1);
+ transitionSet.addTransition(transition2);
+ return transitionSet;
+ }
+ }
+
+ private void setSharedElements(ArrayList<String> accepted, ArrayList<String> localNames) {
+ if (!mAllSharedElementNames.isEmpty()) {
+ ArrayMap<String, View> sharedElements = new ArrayMap<String, View>();
+ getDecor().findNamedViews(sharedElements);
+ if (accepted != null) {
+ for (int i = 0; i < localNames.size(); i++) {
+ String localName = localNames.get(i);
+ String acceptedName = accepted.get(i);
+ if (!localName.equals(acceptedName)) {
+ View view = sharedElements.remove(localName);
+ if (view != null) {
+ sharedElements.put(acceptedName, view);
+ }
+ }
}
}
- });
- }
-
- private void createSharedElementImages(ArrayList<View> accepted, ArrayList<View> rejected,
- ArrayList<String> sharedElementNames, Bundle state) {
- int numSharedElements = sharedElementNames.size();
- Context context = getWindow().getContext();
- int[] parentLoc = new int[2];
- getDecor().getLocationOnScreen(parentLoc);
- for (int i = 0; i < numSharedElements; i++) {
- String name = sharedElementNames.get(i);
- Bundle sharedElementBundle = state.getBundle(name);
- if (sharedElementBundle != null) {
- Bitmap bitmap = sharedElementBundle.getParcelable(KEY_BITMAP);
- ImageView imageView = new ImageView(context);
- imageView.setId(com.android.internal.R.id.shared_element);
- imageView.setScaleType(ImageView.ScaleType.CENTER);
- imageView.setImageBitmap(bitmap);
- imageView.setViewName(name);
- setSharedElementState(imageView, name, state, parentLoc);
- if (mTargetSharedNames.contains(name)) {
- accepted.add(imageView);
- } else {
- rejected.add(imageView);
+ sharedElements.retainAll(mAllSharedElementNames);
+ mListener.remapSharedElements(mAllSharedElementNames, sharedElements);
+ sharedElements.retainAll(mAllSharedElementNames);
+ for (int i = 0; i < mAllSharedElementNames.size(); i++) {
+ String name = mAllSharedElementNames.get(i);
+ View sharedElement = sharedElements.get(name);
+ if (sharedElement != null) {
+ mSharedElementNames.add(name);
+ mSharedElements.add(sharedElement);
}
}
}
}
- private static void setOriginalImageViewState(
- ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalState) {
- for (int i = 0; i < originalState.size(); i++) {
- ImageView imageView = originalState.keyAt(i);
- Pair<ImageView.ScaleType, Matrix> state = originalState.valueAt(i);
- imageView.setScaleType(state.first);
- imageView.setImageMatrix(state.second);
- }
+ protected void setResultReceiver(ResultReceiver resultReceiver) {
+ mResultReceiver = resultReceiver;
}
- private static int scaleTypeToInt(ImageView.ScaleType scaleType) {
- for (int i = 0; i < SCALE_TYPE_VALUES.length; i++) {
- if (scaleType == SCALE_TYPE_VALUES[i]) {
- return i;
- }
- }
- return -1;
- }
+ protected abstract Transition getViewsTransition();
private static class FixedEpicenterCallback extends Transition.EpicenterCallback {
private Rect mEpicenter;
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
new file mode 100644
index 0000000..63019b6
--- /dev/null
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -0,0 +1,204 @@
+/*
+ * 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.app;
+
+import android.os.Bundle;
+import android.os.ResultReceiver;
+import android.util.ArrayMap;
+import android.view.View;
+import android.view.Window;
+
+import java.util.ArrayList;
+
+/**
+ * This class contains all persistence-related functionality for Activity Transitions.
+ * Activities start exit and enter Activity Transitions through this class.
+ */
+class ActivityTransitionState {
+
+ private static final String ENTERING_SHARED_ELEMENTS = "android:enteringSharedElements";
+
+ private static final String ENTERING_MAPPED_FROM = "android:enteringMappedFrom";
+
+ private static final String ENTERING_MAPPED_TO = "android:enteringMappedTo";
+
+ private static final String EXITING_MAPPED_FROM = "android:exitingMappedFrom";
+
+ private static final String EXITING_MAPPED_TO = "android:exitingMappedTo";
+
+ /**
+ * The shared elements that the calling Activity has said that they transferred to this
+ * Activity.
+ */
+ private ArrayList<String> mEnteringNames;
+
+ /**
+ * The shared elements that this Activity as accepted and mapped to local Views.
+ */
+ private ArrayList<String> mEnteringFrom;
+
+ /**
+ * The names of local Views that are mapped to those elements in mEnteringFrom.
+ */
+ private ArrayList<String> mEnteringTo;
+
+ /**
+ * The names of shared elements that were shared to the called Activity.
+ */
+ private ArrayList<String> mExitingFrom;
+
+ /**
+ * The names of local Views that were shared out, mapped to those elements in mExitingFrom.
+ */
+ private ArrayList<String> mExitingTo;
+
+ /**
+ * The ActivityOptions used to call an Activity. Used to make the elements restore
+ * Visibility of exited Views.
+ */
+ private ActivityOptions mCalledActivityOptions;
+
+ /**
+ * We must be able to cancel entering transitions to stop changing the Window to
+ * opaque when we exit before making the Window opaque.
+ */
+ private EnterTransitionCoordinator mEnterTransitionCoordinator;
+
+ /**
+ * ActivityOptions used on entering this Activity.
+ */
+ private ActivityOptions mEnterActivityOptions;
+
+ /**
+ * Has an exit transition been started? If so, we don't want to double-exit.
+ */
+ private boolean mHasExited;
+
+ public ActivityTransitionState() {
+ }
+
+ public void readState(Bundle bundle) {
+ if (bundle != null) {
+ if (mEnterTransitionCoordinator == null || mEnterTransitionCoordinator.isReturning()) {
+ mEnteringNames = bundle.getStringArrayList(ENTERING_SHARED_ELEMENTS);
+ mEnteringFrom = bundle.getStringArrayList(ENTERING_MAPPED_FROM);
+ mEnteringTo = bundle.getStringArrayList(ENTERING_MAPPED_TO);
+ }
+ if (mEnterTransitionCoordinator == null) {
+ mExitingFrom = bundle.getStringArrayList(EXITING_MAPPED_FROM);
+ mExitingTo = bundle.getStringArrayList(EXITING_MAPPED_TO);
+ }
+ }
+ }
+
+ public void saveState(Bundle bundle) {
+ if (mEnteringNames != null) {
+ bundle.putStringArrayList(ENTERING_SHARED_ELEMENTS, mEnteringNames);
+ bundle.putStringArrayList(ENTERING_MAPPED_FROM, mEnteringFrom);
+ bundle.putStringArrayList(ENTERING_MAPPED_TO, mEnteringTo);
+ }
+ if (mExitingFrom != null) {
+ bundle.putStringArrayList(EXITING_MAPPED_FROM, mExitingFrom);
+ bundle.putStringArrayList(EXITING_MAPPED_TO, mExitingTo);
+ }
+ }
+
+ public void setEnterActivityOptions(Activity activity, ActivityOptions options) {
+ if (activity.getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)
+ && options != null && mEnterActivityOptions == null
+ && options.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
+ mEnterActivityOptions = options;
+ if (mEnterActivityOptions.isReturning()) {
+ int result = mEnterActivityOptions.getResultCode();
+ if (result != 0) {
+ activity.onActivityReenter(result, mEnterActivityOptions.getResultData());
+ }
+ }
+ }
+ }
+
+ public void enterReady(Activity activity) {
+ if (mEnterActivityOptions == null) {
+ return;
+ }
+ mHasExited = false;
+ ArrayList<String> sharedElementNames = mEnterActivityOptions.getSharedElementNames();
+ ResultReceiver resultReceiver = mEnterActivityOptions.getResultReceiver();
+ if (mEnterActivityOptions.isReturning()) {
+ if (mCalledActivityOptions != null) {
+ mCalledActivityOptions.dispatchActivityStopped();
+ mCalledActivityOptions = null;
+ }
+ activity.getWindow().getDecorView().setVisibility(View.VISIBLE);
+ mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity,
+ resultReceiver, sharedElementNames, mExitingFrom, mExitingTo);
+ } else {
+ mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity,
+ resultReceiver, sharedElementNames, null, null);
+ mEnteringNames = sharedElementNames;
+ mEnteringFrom = mEnterTransitionCoordinator.getAcceptedNames();
+ mEnteringTo = mEnterTransitionCoordinator.getMappedNames();
+ }
+ mExitingFrom = null;
+ mExitingTo = null;
+ mEnterActivityOptions = null;
+ }
+
+ public void onStop() {
+ if (mCalledActivityOptions != null) {
+ mCalledActivityOptions.dispatchActivityStopped();
+ mCalledActivityOptions = null;
+ }
+ if (mEnterTransitionCoordinator != null) {
+ mEnterTransitionCoordinator.stop();
+ mEnterTransitionCoordinator = null;
+ }
+ }
+
+ public boolean startExitBackTransition(Activity activity) {
+ if (mEnteringNames == null) {
+ return false;
+ } else {
+ if (!mHasExited) {
+ mHasExited = true;
+ if (mEnterTransitionCoordinator != null) {
+ mEnterTransitionCoordinator.stop();
+ mEnterTransitionCoordinator = null;
+ }
+ ArrayMap<String, View> sharedElements = new ArrayMap<String, View>();
+ activity.getWindow().getDecorView().findNamedViews(sharedElements);
+
+ ExitTransitionCoordinator exitCoordinator =
+ new ExitTransitionCoordinator(activity, mEnteringNames, mEnteringFrom,
+ mEnteringTo, true);
+ exitCoordinator.startExit(activity.mResultCode, activity.mResultData);
+ }
+ return true;
+ }
+ }
+
+ public void startExitOutTransition(Activity activity, Bundle options) {
+ if (!activity.getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
+ return;
+ }
+ mCalledActivityOptions = new ActivityOptions(options);
+ if (mCalledActivityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
+ mExitingFrom = mCalledActivityOptions.getSharedElementNames();
+ mExitingTo = mCalledActivityOptions.getLocalSharedElementNames();
+ mCalledActivityOptions.dispatchStartExit();
+ }
+ }
+}
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index d2d8ed1..636205b 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -18,270 +18,414 @@ package android.app;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
-import android.graphics.drawable.ColorDrawable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Matrix;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
import android.os.ResultReceiver;
import android.transition.Transition;
+import android.transition.TransitionManager;
+import android.util.ArrayMap;
+import android.util.Pair;
import android.view.View;
+import android.view.ViewGroupOverlay;
import android.view.ViewTreeObserver;
-import android.view.Window;
+import android.widget.ImageView;
import java.util.ArrayList;
+import java.util.Collection;
/**
* This ActivityTransitionCoordinator is created by the Activity to manage
- * the enter scene and shared element transfer as well as Activity#finishWithTransition
- * exiting the Scene and transferring shared elements back to the called Activity.
+ * the enter scene and shared element transfer into the Scene, either during
+ * launch of an Activity or returning from a launched Activity.
*/
-class EnterTransitionCoordinator extends ActivityTransitionCoordinator
- implements ViewTreeObserver.OnPreDrawListener {
+class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
private static final String TAG = "EnterTransitionCoordinator";
- // The background fade in/out duration. 150ms is pretty quick, but not abrupt.
- private static final int FADE_BACKGROUND_DURATION_MS = 150;
+ private static final long MAX_WAIT_MS = 1500;
- /**
- * The shared element names sent by the ExitTransitionCoordinator and may be
- * shared when exiting back.
- */
- private ArrayList<String> mEnteringSharedElementNames;
-
- /**
- * The Activity that has created this coordinator. This is used solely to make the
- * Window translucent/opaque.
- */
+ private boolean mSharedElementTransitionStarted;
+ private boolean mIsReturning;
private Activity mActivity;
-
- /**
- * True if the Window was opaque at the start and we should make it opaque again after
- * enter transitions have completed.
- */
- private boolean mWasOpaque;
-
- /**
- * During exit, is the background alpha == 0?
- */
- private boolean mBackgroundFadedOut;
-
- /**
- * During exit, has the shared element transition completed?
- */
- private boolean mSharedElementTransitionComplete;
-
- /**
- * Has the exit started? We don't want to accidentally exit multiple times. e.g. when
- * back is hit twice during the exit animation.
- */
- private boolean mExitTransitionStarted;
-
- /**
- * Has the exit transition ended?
- */
- private boolean mExitTransitionComplete;
-
- /**
- * We only want to make the Window transparent and set the background alpha once. After that,
- * the Activity won't want the same enter transition.
- */
- private boolean mMadeReady;
-
- /**
- * True if Window.hasFeature(Window.FEATURE_CONTENT_TRANSITIONS) -- this means that
- * enter and exit transitions should be active.
- */
- private boolean mSupportsTransition;
-
- /**
- * Background alpha animations may complete prior to receiving the callback for
- * onTranslucentConversionComplete. If so, we need to immediately call to make the Window
- * opaque.
- */
- private boolean mMakeOpaque;
-
- public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver) {
- super(activity.getWindow());
+ private boolean mHasStopped;
+ private Handler mHandler;
+ private boolean mIsCanceled;
+
+ public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
+ ArrayList<String> sharedElementNames,
+ ArrayList<String> acceptedNames, ArrayList<String> mappedNames) {
+ super(activity.getWindow(), sharedElementNames, acceptedNames, mappedNames,
+ activity.mTransitionListener);
mActivity = activity;
- setRemoteResultReceiver(resultReceiver);
+ mIsReturning = acceptedNames != null;
+ setResultReceiver(resultReceiver);
+ prepareEnter();
+ Bundle resultReceiverBundle = new Bundle();
+ resultReceiverBundle.putParcelable(KEY_REMOTE_RECEIVER, this);
+ mResultReceiver.send(MSG_SET_REMOTE_RECEIVER, resultReceiverBundle);
+ if (mIsReturning) {
+ mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ cancel();
+ }
+ };
+ mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS);
+ }
}
- public void readyToEnter() {
- if (!mMadeReady) {
- mMadeReady = true;
- mSupportsTransition = getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS);
- if (mSupportsTransition) {
- Window window = getWindow();
- window.getDecorView().getViewTreeObserver().addOnPreDrawListener(this);
- mActivity.overridePendingTransition(0, 0);
- mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
- @Override
- public void onTranslucentConversionComplete(boolean drawComplete) {
- mWasOpaque = true;
- if (mMakeOpaque) {
- mActivity.convertFromTranslucent();
- }
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ switch (resultCode) {
+ case MSG_TAKE_SHARED_ELEMENTS:
+ if (!mIsCanceled) {
+ if (mHandler != null) {
+ mHandler.removeMessages(MSG_CANCEL);
}
- }, null);
- Drawable background = getDecor().getBackground();
- if (background != null) {
- window.setBackgroundDrawable(null);
- background.setAlpha(0);
- window.setBackgroundDrawable(background);
+ onTakeSharedElements(resultData);
}
+ break;
+ case MSG_EXIT_TRANSITION_COMPLETE:
+ if (!mIsCanceled) {
+ if (!mSharedElementTransitionStarted) {
+ send(resultCode, resultData);
+ } else {
+ onRemoteExitTransitionComplete();
+ }
+ }
+ break;
+ case MSG_CANCEL:
+ cancel();
+ break;
+ }
+ }
+
+ private void cancel() {
+ if (!mIsCanceled) {
+ mIsCanceled = true;
+ if (getViewsTransition() == null) {
+ setViewVisibility(mSharedElements, View.VISIBLE);
+ } else {
+ mTransitioningViews.addAll(mSharedElements);
}
+ mSharedElementNames.clear();
+ mSharedElements.clear();
+ mAllSharedElementNames.clear();
+ onTakeSharedElements(null);
+ onRemoteExitTransitionComplete();
}
}
- @Override
- protected void onTakeSharedElements(ArrayList<String> sharedElementNames, Bundle state) {
- mEnteringSharedElementNames = new ArrayList<String>();
- mEnteringSharedElementNames.addAll(sharedElementNames);
- super.onTakeSharedElements(sharedElementNames, state);
+ public boolean isReturning() {
+ return mIsReturning;
}
- @Override
- protected void sharedElementTransitionComplete(Bundle bundle) {
- notifySharedElementTransitionComplete(bundle);
- exitAfterSharedElementTransition();
+ protected void prepareEnter() {
+ setViewVisibility(mSharedElements, View.INVISIBLE);
+ if (getViewsTransition() != null) {
+ setViewVisibility(mTransitioningViews, View.INVISIBLE);
+ }
+ mActivity.overridePendingTransition(0, 0);
+ if (!mIsReturning) {
+ mActivity.convertToTranslucent(null, null);
+ Drawable background = getDecor().getBackground();
+ if (background != null) {
+ getWindow().setBackgroundDrawable(null);
+ background = background.mutate();
+ background.setAlpha(0);
+ getWindow().setBackgroundDrawable(background);
+ }
+ } else {
+ mActivity = null; // all done with it now.
+ }
}
- @Override
- public boolean onPreDraw() {
- getWindow().getDecorView().getViewTreeObserver().removeOnPreDrawListener(this);
- setEnteringViews(readyEnteringViews());
- notifySetListener();
- onPrepareRestore();
- return false;
+ protected void onTakeSharedElements(Bundle sharedElementState) {
+ setEpicenter();
+ // Remove rejected shared elements
+ ArrayList<String> rejectedNames = new ArrayList<String>(mAllSharedElementNames);
+ rejectedNames.removeAll(mSharedElementNames);
+ ArrayList<View> rejectedSnapshots = createSnapshots(sharedElementState, rejectedNames);
+ mListener.handleRejectedSharedElements(rejectedSnapshots);
+ startRejectedAnimations(rejectedSnapshots);
+
+ // Now start shared element transition
+ ArrayList<View> sharedElementSnapshots = createSnapshots(sharedElementState,
+ mSharedElementNames);
+ setViewVisibility(mSharedElements, View.VISIBLE);
+ ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageViewState =
+ setSharedElementState(sharedElementState, sharedElementSnapshots);
+
+ boolean startEnterTransition = allowOverlappingTransitions();
+ boolean startSharedElementTransition = true;
+ Transition transition = beginTransition(startEnterTransition, startSharedElementTransition);
+
+ if (startEnterTransition) {
+ startEnterTransition(transition);
+ }
+
+ setOriginalImageViewState(originalImageViewState);
+
+ if (mResultReceiver != null) {
+ mResultReceiver.send(MSG_HIDE_SHARED_ELEMENTS, null);
+ }
+ mResultReceiver = null; // all done sending messages.
}
- @Override
- public void startExit() {
- if (!mExitTransitionStarted) {
- mExitTransitionStarted = true;
- startExitTransition(mEnteringSharedElementNames);
+ private Transition beginTransition(boolean startEnterTransition,
+ boolean startSharedElementTransition) {
+ Transition sharedElementTransition = null;
+ if (startSharedElementTransition && !mSharedElementNames.isEmpty()) {
+ sharedElementTransition = configureTransition(getSharedElementTransition());
}
+ Transition viewsTransition = null;
+ if (startEnterTransition && !mTransitioningViews.isEmpty()) {
+ viewsTransition = configureTransition(getViewsTransition());
+ viewsTransition = addTargets(viewsTransition, mTransitioningViews);
+ }
+
+ Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
+ if (transition != null) {
+ TransitionManager.beginDelayedTransition(getDecor(), transition);
+ if (startSharedElementTransition && !mSharedElementNames.isEmpty()) {
+ mSharedElements.get(0).invalidate();
+ } else if (startEnterTransition && !mTransitioningViews.isEmpty()) {
+ mTransitioningViews.get(0).invalidate();
+ }
+ }
+ return transition;
}
- @Override
- protected Transition getViewsTransition() {
- if (!mSupportsTransition) {
- return null;
+ private void startEnterTransition(Transition transition) {
+ setViewVisibility(mTransitioningViews, View.VISIBLE);
+ if (!mIsReturning) {
+ Drawable background = getDecor().getBackground();
+ if (background != null) {
+ background = background.mutate();
+ ObjectAnimator animator = ObjectAnimator.ofInt(background, "alpha", 255);
+ animator.setDuration(FADE_BACKGROUND_DURATION_MS);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ makeOpaque();
+ }
+ });
+ animator.start();
+ } else if (transition != null) {
+ transition.addListener(new Transition.TransitionListenerAdapter() {
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ transition.removeListener(this);
+ makeOpaque();
+ }
+ });
+ } else {
+ makeOpaque();
+ }
}
- return getWindow().getEnterTransition();
}
- @Override
- protected Transition getSharedElementTransition() {
- if (!mSupportsTransition) {
- return null;
+ public void stop() {
+ mHasStopped = true;
+ mActivity = null;
+ mIsCanceled = true;
+ mResultReceiver = null;
+ }
+
+ private void makeOpaque() {
+ if (!mHasStopped) {
+ mActivity.convertFromTranslucent();
+ mActivity = null;
}
- return getWindow().getSharedElementEnterTransition();
}
- @Override
- protected void onStartEnterTransition(Transition transition, ArrayList<View> enteringViews) {
- Drawable background = getDecor().getBackground();
- if (background != null) {
- ObjectAnimator animator = ObjectAnimator.ofInt(background, "alpha", 255);
- animator.setDuration(FADE_BACKGROUND_DURATION_MS);
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mMakeOpaque = true;
- if (mWasOpaque) {
- mActivity.convertFromTranslucent();
- }
- }
- });
+ private boolean allowOverlappingTransitions() {
+ return mIsReturning ? getWindow().getAllowExitTransitionOverlap()
+ : getWindow().getAllowEnterTransitionOverlap();
+ }
+
+ private void startRejectedAnimations(final ArrayList<View> rejectedSnapshots) {
+ if (rejectedSnapshots == null || rejectedSnapshots.isEmpty()) {
+ return;
+ }
+ ViewGroupOverlay overlay = getDecor().getOverlay();
+ ObjectAnimator animator = null;
+ int numRejected = rejectedSnapshots.size();
+ for (int i = 0; i < numRejected; i++) {
+ View snapshot = rejectedSnapshots.get(i);
+ overlay.add(snapshot);
+ animator = ObjectAnimator.ofFloat(snapshot, View.ALPHA, 1, 0);
animator.start();
- } else if (mWasOpaque) {
- transition.addListener(new Transition.TransitionListenerAdapter() {
- @Override
- public void onTransitionEnd(Transition transition) {
- mMakeOpaque = true;
- mActivity.convertFromTranslucent();
- }
- });
}
- super.onStartEnterTransition(transition, enteringViews);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ ViewGroupOverlay overlay = getDecor().getOverlay();
+ int numRejected = rejectedSnapshots.size();
+ for (int i = 0; i < numRejected; i++) {
+ overlay.remove(rejectedSnapshots.get(i));
+ }
+ }
+ });
}
- public ArrayList<View> readyEnteringViews() {
- ArrayList<View> enteringViews = new ArrayList<View>();
- getDecor().captureTransitioningViews(enteringViews);
- if (getViewsTransition() != null) {
- setViewVisibility(enteringViews, View.INVISIBLE);
+ protected void onRemoteExitTransitionComplete() {
+ if (!allowOverlappingTransitions()) {
+ boolean startEnterTransition = true;
+ boolean startSharedElementTransition = false;
+ Transition transition = beginTransition(startEnterTransition,
+ startSharedElementTransition);
+ startEnterTransition(transition);
}
- return enteringViews;
}
- @Override
- protected void startExitTransition(ArrayList<String> sharedElements) {
- mMakeOpaque = false;
- notifyPrepareRestore();
+ private ArrayList<View> createSnapshots(Bundle state, Collection<String> names) {
+ int numSharedElements = names.size();
+ if (numSharedElements == 0) {
+ return null;
+ }
+ ArrayList<View> snapshots = new ArrayList<View>(numSharedElements);
+ Context context = getWindow().getContext();
+ int[] parentLoc = new int[2];
+ getDecor().getLocationOnScreen(parentLoc);
+ for (String name: names) {
+ Bundle sharedElementBundle = state.getBundle(name);
+ if (sharedElementBundle != null) {
+ Bitmap bitmap = sharedElementBundle.getParcelable(KEY_BITMAP);
+ View snapshot = new View(context);
+ snapshot.setId(com.android.internal.R.id.shared_element);
+ Resources resources = getWindow().getContext().getResources();
+ snapshot.setBackground(new BitmapDrawable(resources, bitmap));
+ snapshot.setViewName(name);
+ setSharedElementState(snapshot, name, state, parentLoc);
+ snapshots.add(snapshot);
+ }
+ }
+ return snapshots;
+ }
- if (getDecor().getBackground() == null) {
- ColorDrawable black = new ColorDrawable(0xFF000000);
- getWindow().setBackgroundDrawable(black);
+ private static void setSharedElementState(View view, String name, Bundle transitionArgs,
+ int[] parentLoc) {
+ Bundle sharedElementBundle = transitionArgs.getBundle(name);
+ if (sharedElementBundle == null) {
+ return;
}
- if (mWasOpaque) {
- mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
- @Override
- public void onTranslucentConversionComplete(boolean drawComplete) {
- fadeOutBackground();
+
+ if (view instanceof ImageView) {
+ int scaleTypeInt = sharedElementBundle.getInt(KEY_SCALE_TYPE, -1);
+ if (scaleTypeInt >= 0) {
+ ImageView imageView = (ImageView) view;
+ ImageView.ScaleType scaleType = SCALE_TYPE_VALUES[scaleTypeInt];
+ imageView.setScaleType(scaleType);
+ if (scaleType == ImageView.ScaleType.MATRIX) {
+ float[] matrixValues = sharedElementBundle.getFloatArray(KEY_IMAGE_MATRIX);
+ Matrix matrix = new Matrix();
+ matrix.setValues(matrixValues);
+ imageView.setImageMatrix(matrix);
}
- }, null);
- } else {
- fadeOutBackground();
+ }
}
- super.startExitTransition(sharedElements);
+ float z = sharedElementBundle.getFloat(KEY_TRANSLATION_Z);
+ view.setTranslationZ(z);
+
+ int x = sharedElementBundle.getInt(KEY_SCREEN_X);
+ int y = sharedElementBundle.getInt(KEY_SCREEN_Y);
+ int width = sharedElementBundle.getInt(KEY_WIDTH);
+ int height = sharedElementBundle.getInt(KEY_HEIGHT);
+
+ int widthSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
+ int heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
+ view.measure(widthSpec, heightSpec);
+
+ int left = x - parentLoc[0];
+ int top = y - parentLoc[1];
+ int right = left + width;
+ int bottom = top + height;
+ view.layout(left, top, right, bottom);
}
- private void fadeOutBackground() {
- ObjectAnimator animator = ObjectAnimator.ofInt(getDecor().getBackground(),
- "alpha", 0);
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mBackgroundFadedOut = true;
- if (mSharedElementTransitionComplete) {
- EnterTransitionCoordinator.super.onSharedElementTransitionEnd();
+ private ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> setSharedElementState(
+ Bundle sharedElementState, final ArrayList<View> snapshots) {
+ ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageState =
+ new ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>>();
+ if (sharedElementState != null) {
+ int[] tempLoc = new int[2];
+ for (int i = 0; i < mSharedElementNames.size(); i++) {
+ View sharedElement = mSharedElements.get(i);
+ String name = mSharedElementNames.get(i);
+ Pair<ImageView.ScaleType, Matrix> originalState = getOldImageState(sharedElement,
+ name, sharedElementState);
+ if (originalState != null) {
+ originalImageState.put((ImageView) sharedElement, originalState);
}
+ View parent = (View) sharedElement.getParent();
+ parent.getLocationOnScreen(tempLoc);
+ setSharedElementState(sharedElement, name, sharedElementState, tempLoc);
+ sharedElement.requestLayout();
}
- });
- animator.setDuration(FADE_BACKGROUND_DURATION_MS);
- animator.start();
+ }
+ mListener.setSharedElementStart(mSharedElementNames, mSharedElements, snapshots);
+
+ getDecor().getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
+ mListener.setSharedElementEnd(mSharedElementNames, mSharedElements,
+ snapshots);
+ mSharedElementTransitionStarted = true;
+ return true;
+ }
+ }
+ );
+ return originalImageState;
}
- @Override
- protected void onExitTransitionEnd() {
- mExitTransitionComplete = true;
- exitAfterSharedElementTransition();
- super.onExitTransitionEnd();
+ private static Pair<ImageView.ScaleType, Matrix> getOldImageState(View view, String name,
+ Bundle transitionArgs) {
+ if (!(view instanceof ImageView)) {
+ return null;
+ }
+ Bundle bundle = transitionArgs.getBundle(name);
+ int scaleTypeInt = bundle.getInt(KEY_SCALE_TYPE, -1);
+ if (scaleTypeInt < 0) {
+ return null;
+ }
+
+ ImageView imageView = (ImageView) view;
+ ImageView.ScaleType originalScaleType = imageView.getScaleType();
+
+ Matrix originalMatrix = null;
+ if (originalScaleType == ImageView.ScaleType.MATRIX) {
+ originalMatrix = new Matrix(imageView.getImageMatrix());
+ }
+
+ return Pair.create(originalScaleType, originalMatrix);
}
- @Override
- protected void onSharedElementTransitionEnd() {
- mSharedElementTransitionComplete = true;
- if (mBackgroundFadedOut) {
- super.onSharedElementTransitionEnd();
+ private static void setOriginalImageViewState(
+ ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalState) {
+ for (int i = 0; i < originalState.size(); i++) {
+ ImageView imageView = originalState.keyAt(i);
+ Pair<ImageView.ScaleType, Matrix> state = originalState.valueAt(i);
+ imageView.setScaleType(state.first);
+ imageView.setImageMatrix(state.second);
}
}
@Override
- protected boolean allowOverlappingTransitions() {
- return getWindow().getAllowEnterTransitionOverlap();
+ protected Transition getViewsTransition() {
+ return getWindow().getEnterTransition();
}
- private void exitAfterSharedElementTransition() {
- if (mSharedElementTransitionComplete && mExitTransitionComplete && mBackgroundFadedOut) {
- mActivity.finish();
- if (mSupportsTransition) {
- mActivity.overridePendingTransition(0, 0);
- }
- notifyExitTransitionComplete();
- clearConnections();
- }
+ protected Transition getSharedElementTransition() {
+ return getWindow().getSharedElementEnterTransition();
}
}
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index d920787..43a60a3 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -15,11 +15,20 @@
*/
package android.app;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
import android.transition.Transition;
-import android.util.Pair;
+import android.transition.TransitionManager;
import android.view.View;
-import android.view.Window;
+import android.widget.ImageView;
import java.util.ArrayList;
@@ -30,142 +39,245 @@ import java.util.ArrayList;
*/
class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
private static final String TAG = "ExitTransitionCoordinator";
+ private static final long MAX_WAIT_MS = 1500;
- /**
- * The Views that have exited and need to be restored to VISIBLE when returning to the
- * normal state.
- */
- private ArrayList<View> mTransitioningViews;
+ private boolean mExitComplete;
- /**
- * Has the exit started? We don't want to accidentally exit multiple times.
- */
- private boolean mExitStarted;
+ private Bundle mSharedElementBundle;
- /**
- * Has the called Activity's ResultReceiver been set?
- */
- private boolean mIsResultReceiverSet;
+ private boolean mExitNotified;
- /**
- * Has the exit transition completed? If so, we can notify as soon as the ResultReceiver
- * has been set.
- */
- private boolean mExitComplete;
+ private boolean mSharedElementNotified;
- /**
- * Has the shared element transition completed? If so, we can notify as soon as the
- * ResultReceiver has been set.
- */
- private Bundle mSharedElements;
+ private Activity mActivity;
- /**
- * Has the shared element transition completed?
- */
- private boolean mSharedElementsComplete;
+ private boolean mIsBackgroundReady;
+
+ private boolean mIsReturning;
- public ExitTransitionCoordinator(Window window,
- ActivityOptions.ActivityTransitionListener listener) {
- super(window);
- setActivityTransitionListener(listener);
+ private boolean mIsCanceled;
+
+ private Handler mHandler;
+
+ public ExitTransitionCoordinator(Activity activity, ArrayList<String> names,
+ ArrayList<String> accepted, ArrayList<String> mapped, boolean isReturning) {
+ super(activity.getWindow(), names, accepted, mapped, activity.mTransitionListener);
+ mIsReturning = isReturning;
+ mIsBackgroundReady = !mIsReturning;
+ mActivity = activity;
}
@Override
- protected void onSetResultReceiver() {
- mIsResultReceiverSet = true;
- notifyCompletions();
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ switch (resultCode) {
+ case MSG_SET_REMOTE_RECEIVER:
+ mResultReceiver = resultData.getParcelable(KEY_REMOTE_RECEIVER);
+ if (mIsCanceled) {
+ mResultReceiver.send(MSG_CANCEL, null);
+ mResultReceiver = null;
+ } else {
+ if (mHandler != null) {
+ mHandler.removeMessages(MSG_CANCEL);
+ }
+ notifyComplete();
+ }
+ break;
+ case MSG_HIDE_SHARED_ELEMENTS:
+ if (!mIsCanceled) {
+ hideSharedElements();
+ }
+ break;
+ case MSG_START_EXIT_TRANSITION:
+ startExit();
+ break;
+ case MSG_ACTIVITY_STOPPED:
+ setViewVisibility(mTransitioningViews, View.VISIBLE);
+ setViewVisibility(mSharedElements, View.VISIBLE);
+ break;
+ }
}
- @Override
- protected void onPrepareRestore() {
- makeTransitioningViewsInvisible();
- setEnteringViews(mTransitioningViews);
- mTransitioningViews = null;
- super.onPrepareRestore();
+ private void hideSharedElements() {
+ setViewVisibility(mSharedElements, View.INVISIBLE);
}
- @Override
- protected void onTakeSharedElements(ArrayList<String> sharedElementNames, Bundle state) {
- super.onTakeSharedElements(sharedElementNames, state);
- clearConnections();
+ public void startExit() {
+ beginTransition();
+ setViewVisibility(mTransitioningViews, View.INVISIBLE);
}
- @Override
- protected void onActivityStopped() {
- if (getViewsTransition() != null) {
- setViewVisibility(mTransitioningViews, View.VISIBLE);
+ public void startExit(int resultCode, Intent data) {
+ mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ mIsCanceled = true;
+ mActivity.finish();
+ mActivity = null;
+ }
+ };
+ mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS);
+ if (getDecor().getBackground() == null) {
+ ColorDrawable black = new ColorDrawable(0xFF000000);
+ black.setAlpha(0);
+ getWindow().setBackgroundDrawable(black);
+ black.setAlpha(255);
}
- super.onActivityStopped();
+ ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this,
+ mAllSharedElementNames, resultCode, data);
+ mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
+ @Override
+ public void onTranslucentConversionComplete(boolean drawComplete) {
+ if (!mIsCanceled) {
+ fadeOutBackground();
+ }
+ }
+ }, options);
+ startExit();
}
- @Override
- protected void sharedElementTransitionComplete(Bundle bundle) {
- mSharedElements = bundle;
- mSharedElementsComplete = true;
- notifyCompletions();
+ private void fadeOutBackground() {
+ ObjectAnimator animator = ObjectAnimator.ofInt(getDecor().getBackground(),
+ "alpha", 0);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIsBackgroundReady = true;
+ notifyComplete();
+ }
+ });
+ animator.setDuration(FADE_BACKGROUND_DURATION_MS);
+ animator.start();
}
- @Override
- protected void onExitTransitionEnd() {
+ private void beginTransition() {
+ Transition sharedElementTransition = configureTransition(getSharedElementTransition());
+ Transition viewsTransition = configureTransition(getViewsTransition());
+ viewsTransition = addTargets(viewsTransition, mTransitioningViews);
+ if (sharedElementTransition == null) {
+ sharedElementTransitionComplete();
+ } else {
+ sharedElementTransition.addListener(new Transition.TransitionListenerAdapter() {
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ sharedElementTransitionComplete();
+ }
+ });
+ }
+ if (viewsTransition == null) {
+ exitTransitionComplete();
+ } else {
+ viewsTransition.addListener(new Transition.TransitionListenerAdapter() {
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ exitTransitionComplete();
+ }
+ });
+ }
+
+ Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
+ TransitionManager.beginDelayedTransition(getDecor(), transition);
+ }
+
+ private void exitTransitionComplete() {
mExitComplete = true;
- notifyCompletions();
- super.onExitTransitionEnd();
+ notifyComplete();
}
- private void notifyCompletions() {
- if (mIsResultReceiverSet && mSharedElementsComplete) {
- if (mSharedElements != null) {
- notifySharedElementTransitionComplete(mSharedElements);
- mSharedElements = null;
- }
- if (mExitComplete) {
- notifyExitTransitionComplete();
- }
- }
+ protected boolean isReadyToNotify() {
+ return mSharedElementBundle != null && mResultReceiver != null && mIsBackgroundReady;
}
- @Override
- public void startExit() {
- if (!mExitStarted) {
- mExitStarted = true;
- setSharedElements();
- startExitTransition(getSharedElementNames());
+ private void sharedElementTransitionComplete() {
+ Bundle bundle = new Bundle();
+ int[] tempLoc = new int[2];
+ for (int i = 0; i < mSharedElementNames.size(); i++) {
+ View sharedElement = mSharedElements.get(i);
+ String name = mSharedElementNames.get(i);
+ captureSharedElementState(sharedElement, name, bundle, tempLoc);
}
+ mSharedElementBundle = bundle;
+ notifyComplete();
}
- @Override
- protected Transition getViewsTransition() {
- if (!getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
- return null;
+ protected void notifyComplete() {
+ if (isReadyToNotify()) {
+ if (!mSharedElementNotified) {
+ mSharedElementNotified = true;
+ mResultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, mSharedElementBundle);
+ }
+ if (!mExitNotified && mExitComplete) {
+ mExitNotified = true;
+ mResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null);
+ mResultReceiver = null; // done talking
+ if (mIsReturning) {
+ mActivity.finish();
+ mActivity.overridePendingTransition(0, 0);
+ }
+ mActivity = null;
+ }
}
- return getWindow().getExitTransition();
}
- @Override
- protected Transition getSharedElementTransition() {
- if (!getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
- return null;
+ /**
+ * Captures placement information for Views with a shared element name for
+ * Activity Transitions.
+ *
+ * @param view The View to capture the placement information for.
+ * @param name The shared element name in the target Activity to apply the placement
+ * information for.
+ * @param transitionArgs Bundle to store shared element placement information.
+ * @param tempLoc A temporary int[2] for capturing the current location of views.
+ */
+ private static void captureSharedElementState(View view, String name, Bundle transitionArgs,
+ int[] tempLoc) {
+ Bundle sharedElementBundle = new Bundle();
+ view.getLocationOnScreen(tempLoc);
+ float scaleX = view.getScaleX();
+ sharedElementBundle.putInt(KEY_SCREEN_X, tempLoc[0]);
+ int width = Math.round(view.getWidth() * scaleX);
+ sharedElementBundle.putInt(KEY_WIDTH, width);
+
+ float scaleY = view.getScaleY();
+ sharedElementBundle.putInt(KEY_SCREEN_Y, tempLoc[1]);
+ int height = Math.round(view.getHeight() * scaleY);
+ sharedElementBundle.putInt(KEY_HEIGHT, height);
+
+ sharedElementBundle.putFloat(KEY_TRANSLATION_Z, view.getTranslationZ());
+
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ view.draw(canvas);
+ sharedElementBundle.putParcelable(KEY_BITMAP, bitmap);
+
+ if (view instanceof ImageView) {
+ ImageView imageView = (ImageView) view;
+ int scaleTypeInt = scaleTypeToInt(imageView.getScaleType());
+ sharedElementBundle.putInt(KEY_SCALE_TYPE, scaleTypeInt);
+ if (imageView.getScaleType() == ImageView.ScaleType.MATRIX) {
+ float[] matrix = new float[9];
+ imageView.getImageMatrix().getValues(matrix);
+ sharedElementBundle.putFloatArray(KEY_IMAGE_MATRIX, matrix);
+ }
}
- return getWindow().getSharedElementExitTransition();
+
+ transitionArgs.putBundle(name, sharedElementBundle);
}
- private void makeTransitioningViewsInvisible() {
- if (getViewsTransition() != null) {
- setViewVisibility(mTransitioningViews, View.INVISIBLE);
+ private static int scaleTypeToInt(ImageView.ScaleType scaleType) {
+ for (int i = 0; i < SCALE_TYPE_VALUES.length; i++) {
+ if (scaleType == SCALE_TYPE_VALUES[i]) {
+ return i;
+ }
}
+ return -1;
}
@Override
- protected void onStartExitTransition(ArrayList<View> exitingViews) {
- mTransitioningViews = new ArrayList<View>();
- if (exitingViews != null) {
- mTransitioningViews.addAll(exitingViews);
- }
- mTransitioningViews.addAll(getSharedElements());
+ protected Transition getViewsTransition() {
+ return getWindow().getExitTransition();
}
- @Override
- protected boolean allowOverlappingTransitions() {
- return getWindow().getAllowExitTransitionOverlap();
+ protected Transition getSharedElementTransition() {
+ return getWindow().getSharedElementExitTransition();
}
}
diff --git a/core/java/android/app/FragmentBreadCrumbs.java b/core/java/android/app/FragmentBreadCrumbs.java
index e4de7af..ab0fc66 100644
--- a/core/java/android/app/FragmentBreadCrumbs.java
+++ b/core/java/android/app/FragmentBreadCrumbs.java
@@ -37,7 +37,10 @@ import android.widget.TextView;
*
* <p>The default style for this view is
* {@link android.R.style#Widget_FragmentBreadCrumbs}.
+ *
+ * @deprecated This widget is no longer supported.
*/
+@Deprecated
public class FragmentBreadCrumbs extends ViewGroup
implements FragmentManager.OnBackStackChangedListener {
Activity mActivity;
@@ -88,6 +91,9 @@ public class FragmentBreadCrumbs extends ViewGroup
this(context, attrs, defStyleAttr, 0);
}
+ /**
+ * @hide
+ */
public FragmentBreadCrumbs(
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
diff --git a/core/java/android/app/SharedElementListener.java b/core/java/android/app/SharedElementListener.java
new file mode 100644
index 0000000..d4bc019
--- /dev/null
+++ b/core/java/android/app/SharedElementListener.java
@@ -0,0 +1,87 @@
+/*
+ * 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.app;
+
+import android.view.View;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Listener provided in
+ * {@link Activity#setSharedElementListener(SharedElementListener)}
+ * to monitor the Activity transitions. The events can be used to customize or override Activity
+ * Transition behavior.
+ */
+public class SharedElementListener {
+ /**
+ * Called to allow the listener to customize the start state of the shared element for
+ * the shared element entering transition. By default, the shared element is placed in
+ * the position and with the size of the shared element in the calling Activity or Fragment.
+ *
+ * @param sharedElementNames The names of the shared elements that were accepted into
+ * the View hierarchy.
+ * @param sharedElements The shared elements that are part of the View hierarchy.
+ * @param sharedElementSnapshots The Views containing snap shots of the shared element
+ * from the launching Window. These elements will not
+ * be part of the scene, but will be positioned relative
+ * to the Window decor View.
+ */
+ public void setSharedElementStart(List<String> sharedElementNames,
+ List<View> sharedElements, List<View> sharedElementSnapshots) {}
+
+ /**
+ * Called to allow the listener to customize the end state of the shared element for
+ * the shared element entering transition.
+ *
+ * @param sharedElementNames The names of the shared elements that were accepted into
+ * the View hierarchy.
+ * @param sharedElements The shared elements that are part of the View hierarchy.
+ * @param sharedElementSnapshots The Views containing snap shots of the shared element
+ * from the launching Window. These elements will not
+ * be part of the scene, but will be positioned relative
+ * to the Window decor View.
+ */
+ public void setSharedElementEnd(List<String> sharedElementNames,
+ List<View> sharedElements, List<View> sharedElementSnapshots) {}
+
+ /**
+ * If nothing is done, all shared elements that were not accepted by
+ * {@link #remapSharedElements(java.util.List, java.util.Map)} will be Transitioned
+ * out of the entering scene automatically. Any elements removed from
+ * rejectedSharedElements must be handled by the ActivityTransitionListener.
+ * <p>Views in rejectedSharedElements will have their position and size set to the
+ * position of the calling shared element, relative to the Window decor View. This
+ * view may be safely added to the decor View's overlay to remain in position.</p>
+ *
+ * @param rejectedSharedElements Views containing visual information of shared elements
+ * that are not part of the entering scene. These Views
+ * are positioned relative to the Window decor View. A
+ * View removed from this list will not be transitioned
+ * automatically.
+ */
+ public void handleRejectedSharedElements(List<View> rejectedSharedElements) {}
+
+ /**
+ * Lets the ActivityTransitionListener adjust the mapping of shared element names to
+ * Views.
+ * @param names The names of all shared elements transferred from the calling Activity
+ * to the started Activity.
+ * @param sharedElements The mapping of shared element names to Views. The best guess
+ * will be filled into sharedElements based on the View names.
+ */
+ public void remapSharedElements(List<String> names, Map<String, View> sharedElements) {}
+}
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 49b156d..3dd7094 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -31,6 +31,8 @@ interface IBluetoothGatt {
void startScan(in int appIf, in boolean isServer);
void startScanWithUuids(in int appIf, in boolean isServer, in ParcelUuid[] ids);
+ void startScanWithUuidsScanParam(in int appIf, in boolean isServer,
+ in ParcelUuid[] ids, int scanWindow, int scanInterval);
void stopScan(in int appIf, in boolean isServer);
void registerClient(in ParcelUuid appId, in IBluetoothGattCallback callback);
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 499de17..1692a79 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1475,21 +1475,12 @@ public class Resources {
* in length to {@code attrs} or {@code null}. All values
* must be of type {@link TypedValue#TYPE_ATTRIBUTE}.
* @param attrs The desired attributes to be retrieved.
- * @param defStyleAttr An attribute in the current theme that contains a
- * reference to a style resource that supplies
- * defaults values for the TypedArray. Can be
- * 0 to not look for defaults.
- * @param defStyleRes A resource identifier of a style resource that
- * supplies default values for the TypedArray,
- * used only if defStyleAttr is 0 or can not be found
- * in the theme. Can be 0 to not look for defaults.
* @return Returns a TypedArray holding an array of the attribute
* values. Be sure to call {@link TypedArray#recycle()}
* when done with it.
* @hide
*/
- public TypedArray resolveAttributes(int[] values, int[] attrs,
- int defStyleAttr, int defStyleRes) {
+ public TypedArray resolveAttributes(int[] values, int[] attrs) {
final int len = attrs.length;
if (values != null && len != values.length) {
throw new IllegalArgumentException(
@@ -1497,8 +1488,7 @@ public class Resources {
}
final TypedArray array = TypedArray.obtain(Resources.this, len);
- AssetManager.resolveAttrs(mTheme, defStyleAttr, defStyleRes,
- values, attrs, array.mData, array.mIndices);
+ AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
array.mTheme = this;
array.mXml = null;
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 15337ce..20dcf83 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -885,13 +885,13 @@ public class TypedArray {
/**
* Extracts theme attributes from a typed array for later resolution using
- * {@link Theme#resolveAttributes(int[], int[], int, int)}.
+ * {@link Theme#resolveAttributes(int[], int[])}. Removes the entries from
+ * the typed array so that subsequent calls to typed getters will return the
+ * default value without crashing.
*
- * @param array An array to populate with theme attributes. If the array is
- * null or not large enough, a new array will be returned.
* @return an array of length {@link #getIndexCount()} populated with theme
- * attributes, or null if there are no theme attributes in the
- * typed array
+ * attributes, or null if there are no theme attributes in the typed
+ * array
* @hide
*/
public int[] extractThemeAttrs() {
@@ -901,15 +901,27 @@ public class TypedArray {
int[] attrs = null;
+ final int[] data = mData;
final int N = length();
for (int i = 0; i < N; i++) {
- final int attrId = getThemeAttributeId(i, 0);
- if (attrId != 0) {
- if (attrs == null) {
- attrs = new int[N];
- }
- attrs[i] = attrId;
+ final int index = i * AssetManager.STYLE_NUM_ENTRIES;
+ if (data[index + AssetManager.STYLE_TYPE] != TypedValue.TYPE_ATTRIBUTE) {
+ continue;
+ }
+
+ // Null the entry so that we can safely call getZzz().
+ data[index + AssetManager.STYLE_TYPE] = TypedValue.TYPE_NULL;
+
+ final int attr = data[index + AssetManager.STYLE_DATA];
+ if (attr == 0) {
+ // This attribute is useless!
+ continue;
+ }
+
+ if (attrs == null) {
+ attrs = new int[N];
}
+ attrs[i] = attr;
}
return attrs;
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 5f2af8c..b1c1005 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -307,16 +307,14 @@ public final class CameraCharacteristics extends CameraMetadata {
* <li>The sizes will be sorted by increasing pixel area (width x height).
* If several resolutions have the same area, they will be sorted by increasing width.</li>
* <li>The aspect ratio of the largest thumbnail size will be same as the
- * aspect ratio of largest JPEG output size in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations}.
+ * aspect ratio of largest JPEG output size in android.scaler.availableStreamConfigurations.
* The largest size is defined as the size that has the largest pixel area
* in a given size list.</li>
- * <li>Each output JPEG size in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations} will have at least
+ * <li>Each output JPEG size in android.scaler.availableStreamConfigurations will have at least
* one corresponding size that has the same aspect ratio in availableThumbnailSizes,
* and vice versa.</li>
* <li>All non (0, 0) sizes will have non-zero widths and heights.</li>
* </ul>
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
*/
public static final Key<android.hardware.camera2.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES =
new Key<android.hardware.camera2.Size[]>("android.jpeg.availableThumbnailSizes", android.hardware.camera2.Size[].class);
@@ -445,8 +443,10 @@ public final class CameraCharacteristics extends CameraMetadata {
* working at that point; DO NOT USE without careful
* consideration of future support.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * @deprecated
* @hide
*/
+ @Deprecated
public static final Key<Byte> QUIRKS_USE_PARTIAL_RESULT =
new Key<Byte>("android.quirks.usePartialResult", byte.class);
@@ -461,8 +461,8 @@ public final class CameraCharacteristics extends CameraMetadata {
* <p>This lists the upper bound of the number of output streams supported by
* the camera device. Using more streams simultaneously may require more hardware and
* CPU resources that will consume more power. The image format for a output stream can
- * be any supported format provided by {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations}.
- * The formats defined in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations} can be catergorized
+ * be any supported format provided by android.scaler.availableStreamConfigurations.
+ * The formats defined in android.scaler.availableStreamConfigurations can be catergorized
* into the 3 stream types as below:</p>
* <ul>
* <li>Processed (but stalling): any non-RAW format with a stallDurations &gt; 0.
@@ -471,8 +471,6 @@ public final class CameraCharacteristics extends CameraMetadata {
* <li>Processed (but not-stalling): any non-RAW format without a stall duration.
* Typically ImageFormat#YUV_420_888, ImageFormat#NV21, ImageFormat#YV12.</li>
* </ul>
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
*/
public static final Key<int[]> REQUEST_MAX_NUM_OUTPUT_STREAMS =
new Key<int[]>("android.request.maxNumOutputStreams", int[].class);
@@ -483,14 +481,12 @@ public final class CameraCharacteristics extends CameraMetadata {
* <p>When set to 0, it means no input stream is supported.</p>
* <p>The image format for a input stream can be any supported
* format provided by
- * {@link CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP android.scaler.availableInputOutputFormatsMap}. When using an
+ * android.scaler.availableInputOutputFormatsMap. When using an
* input stream, there must be at least one output stream
* configured to to receive the reprocessed images.</p>
* <p>For example, for Zero Shutter Lag (ZSL) still capture use case, the input
* stream image format will be RAW_OPAQUE, the associated output stream image format
* should be JPEG.</p>
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP
*/
public static final Key<Integer> REQUEST_MAX_NUM_INPUT_STREAMS =
new Key<Integer>("android.request.maxNumInputStreams", int.class);
@@ -629,22 +625,26 @@ public final class CameraCharacteristics extends CameraMetadata {
* camera device for output streams.</p>
* <p>All camera devices will support JPEG and YUV_420_888 formats.</p>
* <p>When set to YUV_420_888, application can access the YUV420 data directly.</p>
+ * @deprecated
+ * @hide
*/
+ @Deprecated
public static final Key<int[]> SCALER_AVAILABLE_FORMATS =
new Key<int[]>("android.scaler.availableFormats", int[].class);
/**
* <p>The minimum frame duration that is supported
- * for each resolution in {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_SIZES android.scaler.availableJpegSizes}.</p>
+ * for each resolution in android.scaler.availableJpegSizes.</p>
* <p>This corresponds to the minimum steady-state frame duration when only
* that JPEG stream is active and captured in a burst, with all
* processing (typically in android.*.mode) set to FAST.</p>
* <p>When multiple streams are configured, the minimum
* frame duration will be &gt;= max(individual stream min
* durations)</p>
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_JPEG_SIZES
+ * @deprecated
+ * @hide
*/
+ @Deprecated
public static final Key<long[]> SCALER_AVAILABLE_JPEG_MIN_DURATIONS =
new Key<long[]>("android.scaler.availableJpegMinDurations", long[].class);
@@ -654,7 +654,10 @@ public final class CameraCharacteristics extends CameraMetadata {
* sensor maximum resolution (defined by {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}).</p>
*
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @deprecated
+ * @hide
*/
+ @Deprecated
public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_JPEG_SIZES =
new Key<android.hardware.camera2.Size[]>("android.scaler.availableJpegSizes", android.hardware.camera2.Size[].class);
@@ -669,16 +672,17 @@ public final class CameraCharacteristics extends CameraMetadata {
/**
* <p>For each available processed output size (defined in
- * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES android.scaler.availableProcessedSizes}), this property lists the
+ * android.scaler.availableProcessedSizes), this property lists the
* minimum supportable frame duration for that size.</p>
* <p>This should correspond to the frame duration when only that processed
* stream is active, with all processing (typically in android.*.mode)
* set to FAST.</p>
* <p>When multiple streams are configured, the minimum frame duration will
* be &gt;= max(individual stream min durations).</p>
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES
+ * @deprecated
+ * @hide
*/
+ @Deprecated
public static final Key<long[]> SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS =
new Key<long[]>("android.scaler.availableProcessedMinDurations", long[].class);
@@ -696,7 +700,10 @@ public final class CameraCharacteristics extends CameraMetadata {
* can provide.</p>
* <p>Please reference the documentation for the image data destination to
* check if it limits the maximum size for image data.</p>
+ * @deprecated
+ * @hide
*/
+ @Deprecated
public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_PROCESSED_SIZES =
new Key<android.hardware.camera2.Size[]>("android.scaler.availableProcessedSizes", android.hardware.camera2.Size[].class);
@@ -746,13 +753,14 @@ public final class CameraCharacteristics extends CameraMetadata {
* </table>
* <p>For ZSL-capable camera devices, using the RAW_OPAQUE format
* as either input or output will never hurt maximum frame rate (i.e.
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations} will not have RAW_OPAQUE).</p>
+ * StreamConfigurationMap#getOutputStallDuration(int,Size)
+ * for a <code>format =</code> RAW_OPAQUE is always 0).</p>
* <p>Attempting to configure an input stream with output streams not
* listed as available in this map is not valid.</p>
- * <p>TODO: Add java type mapping for this property.</p>
+ * <p>TODO: typedef to ReprocessFormatMap</p>
*
* @see CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS
- * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
+ * @hide
*/
public static final Key<int[]> SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP =
new Key<int[]>("android.scaler.availableInputOutputFormatsMap", int[].class);
@@ -775,7 +783,7 @@ public final class CameraCharacteristics extends CameraMetadata {
* check if it limits the maximum size for image data.</p>
* <p>Not all output formats may be supported in a configuration with
* an input stream of a particular format. For more details, see
- * {@link CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP android.scaler.availableInputOutputFormatsMap}.</p>
+ * android.scaler.availableInputOutputFormatsMap.</p>
* <p>The following table describes the minimum required output stream
* configurations based on the hardware level
* ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel}):</p>
@@ -844,13 +852,11 @@ public final class CameraCharacteristics extends CameraMetadata {
*
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
- * @see CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
- * @see #SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT
- * @see #SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT
+ * @hide
*/
- public static final Key<int[]> SCALER_AVAILABLE_STREAM_CONFIGURATIONS =
- new Key<int[]>("android.scaler.availableStreamConfigurations", int[].class);
+ public static final Key<android.hardware.camera2.params.StreamConfiguration[]> SCALER_AVAILABLE_STREAM_CONFIGURATIONS =
+ new Key<android.hardware.camera2.params.StreamConfiguration[]>("android.scaler.availableStreamConfigurations", android.hardware.camera2.params.StreamConfiguration[].class);
/**
* <p>This lists the minimum frame duration for each
@@ -863,14 +869,16 @@ public final class CameraCharacteristics extends CameraMetadata {
* <p>The minimum frame duration of a stream (of a particular format, size)
* is the same regardless of whether the stream is input or output.</p>
* <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} and
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations} for more details about
+ * android.scaler.availableStallDurations for more details about
* calculating the max frame rate.</p>
+ * <p>(Keep in sync with
+ * StreamConfigurationMap#getOutputMinFrameDuration)</p>
*
- * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
* @see CaptureRequest#SENSOR_FRAME_DURATION
+ * @hide
*/
- public static final Key<long[]> SCALER_AVAILABLE_MIN_FRAME_DURATIONS =
- new Key<long[]>("android.scaler.availableMinFrameDurations", long[].class);
+ public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> SCALER_AVAILABLE_MIN_FRAME_DURATIONS =
+ new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.scaler.availableMinFrameDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class);
/**
* <p>This lists the maximum stall duration for each
@@ -929,12 +937,105 @@ public final class CameraCharacteristics extends CameraMetadata {
* for more details.</p>
* <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} for more information about
* calculating the max frame rate (absent stalls).</p>
+ * <p>(Keep up to date with
+ * StreamConfigurationMap#getOutputStallDuration(int, Size) )</p>
*
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
* @see CaptureRequest#SENSOR_FRAME_DURATION
+ * @hide
*/
- public static final Key<long[]> SCALER_AVAILABLE_STALL_DURATIONS =
- new Key<long[]>("android.scaler.availableStallDurations", long[].class);
+ public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> SCALER_AVAILABLE_STALL_DURATIONS =
+ new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.scaler.availableStallDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class);
+
+ /**
+ * <p>The available stream configurations that this
+ * camera device supports; also includes the minimum frame durations
+ * and the stall durations for each format/size combination.</p>
+ * <p>All camera devices will support sensor maximum resolution (defined by
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}) for the JPEG format.</p>
+ * <p>For a given use case, the actual maximum supported resolution
+ * may be lower than what is listed here, depending on the destination
+ * Surface for the image data. For example, for recording video,
+ * the video encoder chosen may have a maximum size limit (e.g. 1080p)
+ * smaller than what the camera (e.g. maximum resolution is 3264x2448)
+ * can provide.</p>
+ * <p>Please reference the documentation for the image data destination to
+ * check if it limits the maximum size for image data.</p>
+ * <p>Not all output formats may be supported in a configuration with
+ * an input stream of a particular format. For more details, see
+ * android.scaler.availableInputOutputFormatsMap.</p>
+ * <p>The following table describes the minimum required output stream
+ * configurations based on the hardware level
+ * ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel}):</p>
+ * <table>
+ * <thead>
+ * <tr>
+ * <th align="center">Format</th>
+ * <th align="center">Size</th>
+ * <th align="center">Hardware Level</th>
+ * <th align="center">Notes</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td align="center">JPEG</td>
+ * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
+ * <td align="center">Any</td>
+ * <td align="center"></td>
+ * </tr>
+ * <tr>
+ * <td align="center">JPEG</td>
+ * <td align="center">1920x1080 (1080p)</td>
+ * <td align="center">Any</td>
+ * <td align="center">if 1080p &lt;= activeArraySize</td>
+ * </tr>
+ * <tr>
+ * <td align="center">JPEG</td>
+ * <td align="center">1280x720 (720)</td>
+ * <td align="center">Any</td>
+ * <td align="center">if 720p &lt;= activeArraySize</td>
+ * </tr>
+ * <tr>
+ * <td align="center">JPEG</td>
+ * <td align="center">640x480 (480p)</td>
+ * <td align="center">Any</td>
+ * <td align="center">if 480p &lt;= activeArraySize</td>
+ * </tr>
+ * <tr>
+ * <td align="center">JPEG</td>
+ * <td align="center">320x240 (240p)</td>
+ * <td align="center">Any</td>
+ * <td align="center">if 240p &lt;= activeArraySize</td>
+ * </tr>
+ * <tr>
+ * <td align="center">YUV_420_888</td>
+ * <td align="center">all output sizes available for JPEG</td>
+ * <td align="center">FULL</td>
+ * <td align="center"></td>
+ * </tr>
+ * <tr>
+ * <td align="center">YUV_420_888</td>
+ * <td align="center">all output sizes available for JPEG, up to the maximum video size</td>
+ * <td align="center">LIMITED</td>
+ * <td align="center"></td>
+ * </tr>
+ * <tr>
+ * <td align="center">IMPLEMENTATION_DEFINED</td>
+ * <td align="center">same as YUV_420_888</td>
+ * <td align="center">Any</td>
+ * <td align="center"></td>
+ * </tr>
+ * </tbody>
+ * </table>
+ * <p>Refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} for additional
+ * mandatory stream configurations on a per-capability basis.</p>
+ *
+ * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ */
+ public static final Key<android.hardware.camera2.params.StreamConfigurationMap> SCALER_STREAM_CONFIGURATION_MAP =
+ new Key<android.hardware.camera2.params.StreamConfigurationMap>("android.scaler.streamConfigurationMap", android.hardware.camera2.params.StreamConfigurationMap.class);
/**
* <p>Area of raw data which corresponds to only
@@ -982,13 +1083,9 @@ public final class CameraCharacteristics extends CameraMetadata {
* being clipped to the maximum. See that control
* for a full definition of frame durations.</p>
* <p>Refer to
- * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS android.scaler.availableProcessedMinDurations},
- * {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS android.scaler.availableJpegMinDurations}, and
- * android.scaler.availableRawMinDurations for the minimum
- * frame duration values.</p>
+ * StreamConfigurationMap#getOutputMinFrameDuration(int,Size)
+ * for the minimum frame duration values.</p>
*
- * @see CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS
- * @see CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS
* @see CaptureRequest#SENSOR_FRAME_DURATION
*/
public static final Key<Long> SENSOR_INFO_MAX_FRAME_DURATION =
@@ -1007,9 +1104,7 @@ public final class CameraCharacteristics extends CameraMetadata {
* including black calibration pixels.</p>
* <p>Maximum output resolution for raw format must
* match this in
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations}.</p>
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ * android.scaler.availableStreamConfigurations.</p>
*/
public static final Key<android.hardware.camera2.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE =
new Key<android.hardware.camera2.Size>("android.sensor.info.pixelArraySize", android.hardware.camera2.Size.class);
@@ -1420,4 +1515,13 @@ public final class CameraCharacteristics extends CameraMetadata {
/*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* End generated code
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
+
+
+
+
+
+
+
+
+
}
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 9d0e0e1..ca03dae 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -16,6 +16,8 @@
package android.hardware.camera2;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.graphics.ImageFormat;
import android.os.Handler;
import android.view.Surface;
@@ -147,7 +149,7 @@ public interface CameraDevice extends AutoCloseable {
* the size of the Surface with
* {@link android.view.SurfaceHolder#setFixedSize} to be one of the
* supported
- * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES processed sizes}
+ * {@link StreamConfigurationMap#getOutputSizes(Class) processed sizes}
* before calling {@link android.view.SurfaceHolder#getSurface}.</li>
*
* <li>For accessing through an OpenGL texture via a
@@ -155,14 +157,14 @@ public interface CameraDevice extends AutoCloseable {
* the SurfaceTexture with
* {@link android.graphics.SurfaceTexture#setDefaultBufferSize} to be one
* of the supported
- * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES processed sizes}
+ * {@link StreamConfigurationMap#getOutputSizes(Class) processed sizes}
* before creating a Surface from the SurfaceTexture with
* {@link Surface#Surface}.</li>
*
* <li>For recording with {@link android.media.MediaCodec}: Call
* {@link android.media.MediaCodec#createInputSurface} after configuring
* the media codec to use one of the
- * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES processed sizes}
+ * {@link StreamConfigurationMap#getOutputSizes(Class) processed sizes}
* </li>
*
* <li>For recording with {@link android.media.MediaRecorder}: TODO</li>
@@ -171,18 +173,15 @@ public interface CameraDevice extends AutoCloseable {
* Create a RenderScript
* {@link android.renderscript.Allocation Allocation} with a supported YUV
* type, the IO_INPUT flag, and one of the supported
- * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES processed sizes}. Then
+ * {@link StreamConfigurationMap#getOutputSizes(int) processed sizes}. Then
* obtain the Surface with
* {@link android.renderscript.Allocation#getSurface}.</li>
*
- * <li>For access to uncompressed or JPEG data in the application: Create a
- * {@link android.media.ImageReader} object with the desired
- * {@link CameraCharacteristics#SCALER_AVAILABLE_FORMATS image format}, and a
- * size from the matching
- * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES processed},
- * {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_SIZES jpeg}. Then obtain
- * a Surface from it.</li>
- *
+ * <li>For access to uncompressed or {@link ImageFormat#JPEG JPEG} data in the application:
+ * Create a {@link android.media.ImageReader} object with the desired
+ * {@link StreamConfigurationMap#getOutputFormats() image format}, and a size from the matching
+ * {@link StreamConfigurationMap#getOutputSizes(int) processed size} and {@code format}.
+ * Then obtain a {@link Surface} from it.</li>
* </ul>
*
* </p>
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 6659278..a11390d 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -446,20 +446,6 @@ public abstract class CameraMetadata {
public static final int REQUEST_AVAILABLE_CAPABILITIES_DNG = 5;
//
- // Enumeration values for CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
- //
-
- /**
- * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
- */
- public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT = 0;
-
- /**
- * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
- */
- public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT = 1;
-
- //
// Enumeration values for CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
//
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 0ca9161..8ae21f3 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1185,7 +1185,8 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
* cannot process more than 1 capture at a time.</li>
* </ul>
* <p>The necessary information for the application, given the model above,
- * is provided via the {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} field.
+ * is provided via the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} field
+ * using StreamConfigurationMap#getOutputMinFrameDuration(int, Size).
* These are used to determine the maximum frame rate / minimum frame
* duration that is possible for a given stream configuration.</p>
* <p>Specifically, the application can use the following rules to
@@ -1195,7 +1196,8 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
* <li>Let the set of currently configured input/output streams
* be called <code>S</code>.</li>
* <li>Find the minimum frame durations for each stream in <code>S</code>, by
- * looking it up in {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} (with
+ * looking it up in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} using
+ * StreamConfigurationMap#getOutputMinFrameDuration(int, Size) (with
* its respective size/format). Let this set of frame durations be called
* <code>F</code>.</li>
* <li>For any given request <code>R</code>, the minimum frame duration allowed
@@ -1203,7 +1205,8 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
* used in <code>R</code> be called <code>S_r</code>.</li>
* </ol>
* <p>If none of the streams in <code>S_r</code> have a stall time (listed in
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}), then the frame duration in
+ * StreamConfigurationMap#getOutputStallDuration(int,Size) using its
+ * respective size/format), then the frame duration in
* <code>F</code> determines the steady state frame rate that the application will
* get if it uses <code>R</code> as a repeating request. Let this special kind
* of request be called <code>Rsimple</code>.</p>
@@ -1214,10 +1217,9 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
* if all buffers from the previous <code>Rstall</code> have already been
* delivered.</p>
* <p>For more details about stalling, see
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}.</p>
+ * StreamConfigurationMap#getOutputStallDuration(int,Size).</p>
*
- * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
- * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
+ * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
*/
public static final Key<Long> SENSOR_FRAME_DURATION =
new Key<Long>("android.sensor.frameDuration", long.class);
@@ -1516,4 +1518,12 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
/*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* End generated code
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
+
+
+
+
+
+
+
+
}
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 42a3de8..0160622 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -216,18 +216,6 @@ public final class CaptureResult extends CameraMetadata {
new Key<float[]>("android.colorCorrection.gains", float[].class);
/**
- * <p>The ID sent with the latest
- * CAMERA2_TRIGGER_PRECAPTURE_METERING call</p>
- * <p>Must be 0 if no
- * CAMERA2_TRIGGER_PRECAPTURE_METERING trigger received yet
- * by HAL. Always updated even if AE algorithm ignores the
- * trigger</p>
- * @hide
- */
- public static final Key<Integer> CONTROL_AE_PRECAPTURE_ID =
- new Key<Integer>("android.control.aePrecaptureId", int.class);
-
- /**
* <p>The desired setting for the camera device's auto-exposure
* algorithm's antibanding compensation.</p>
* <p>Some kinds of lighting fixtures, such as some fluorescent
@@ -1068,17 +1056,6 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.control.afState", int.class);
/**
- * <p>The ID sent with the latest
- * CAMERA2_TRIGGER_AUTOFOCUS call</p>
- * <p>Must be 0 if no CAMERA2_TRIGGER_AUTOFOCUS trigger
- * received yet by HAL. Always updated even if AF algorithm
- * ignores the trigger</p>
- * @hide
- */
- public static final Key<Integer> CONTROL_AF_TRIGGER_ID =
- new Key<Integer>("android.control.afTriggerId", int.class);
-
- /**
* <p>Whether AWB is currently locked to its
* latest calculated values.</p>
* <p>Note that AWB lock is only meaningful for AUTO
@@ -1713,8 +1690,10 @@ public final class CaptureResult extends CameraMetadata {
* capture must arrive before the FINAL buffer for that capture. This entry may
* only be used by the camera device if quirks.usePartialResult is set to 1.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * @deprecated
* @hide
*/
+ @Deprecated
public static final Key<Boolean> QUIRKS_PARTIAL_RESULT =
new Key<Boolean>("android.quirks.partialResult", boolean.class);
@@ -1834,7 +1813,8 @@ public final class CaptureResult extends CameraMetadata {
* cannot process more than 1 capture at a time.</li>
* </ul>
* <p>The necessary information for the application, given the model above,
- * is provided via the {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} field.
+ * is provided via the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} field
+ * using StreamConfigurationMap#getOutputMinFrameDuration(int, Size).
* These are used to determine the maximum frame rate / minimum frame
* duration that is possible for a given stream configuration.</p>
* <p>Specifically, the application can use the following rules to
@@ -1844,7 +1824,8 @@ public final class CaptureResult extends CameraMetadata {
* <li>Let the set of currently configured input/output streams
* be called <code>S</code>.</li>
* <li>Find the minimum frame durations for each stream in <code>S</code>, by
- * looking it up in {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} (with
+ * looking it up in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} using
+ * StreamConfigurationMap#getOutputMinFrameDuration(int, Size) (with
* its respective size/format). Let this set of frame durations be called
* <code>F</code>.</li>
* <li>For any given request <code>R</code>, the minimum frame duration allowed
@@ -1852,7 +1833,8 @@ public final class CaptureResult extends CameraMetadata {
* used in <code>R</code> be called <code>S_r</code>.</li>
* </ol>
* <p>If none of the streams in <code>S_r</code> have a stall time (listed in
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}), then the frame duration in
+ * StreamConfigurationMap#getOutputStallDuration(int,Size) using its
+ * respective size/format), then the frame duration in
* <code>F</code> determines the steady state frame rate that the application will
* get if it uses <code>R</code> as a repeating request. Let this special kind
* of request be called <code>Rsimple</code>.</p>
@@ -1863,10 +1845,9 @@ public final class CaptureResult extends CameraMetadata {
* if all buffers from the previous <code>Rstall</code> have already been
* delivered.</p>
* <p>For more details about stalling, see
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}.</p>
+ * StreamConfigurationMap#getOutputStallDuration(int,Size).</p>
*
- * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
- * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
+ * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
*/
public static final Key<Long> SENSOR_FRAME_DURATION =
new Key<Long>("android.sensor.frameDuration", long.class);
@@ -2141,8 +2122,10 @@ public final class CaptureResult extends CameraMetadata {
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @deprecated
* @hide
*/
+ @Deprecated
public static final Key<float[]> STATISTICS_PREDICTED_COLOR_GAINS =
new Key<float[]>("android.statistics.predictedColorGains", float[].class);
@@ -2163,8 +2146,10 @@ public final class CaptureResult extends CameraMetadata {
* <p>This value should always be calculated by the AWB block,
* regardless of the android.control.* current values.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * @deprecated
* @hide
*/
+ @Deprecated
public static final Key<Rational[]> STATISTICS_PREDICTED_COLOR_TRANSFORM =
new Key<Rational[]>("android.statistics.predictedColorTransform", Rational[].class);
@@ -2441,6 +2426,14 @@ public final class CaptureResult extends CameraMetadata {
* End generated code
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
+
+
+
+
+
+
+
+
/**
* <p>
* List of the {@link Face Faces} detected through camera face detection
diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
index d77f3d1..0815170 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -20,7 +20,7 @@ import android.view.Surface;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.LongParcelable;
+import android.hardware.camera2.utils.LongParcelable;
/** @hide */
interface ICameraDeviceUser
diff --git a/core/java/android/hardware/camera2/StreamConfigurationMap.java b/core/java/android/hardware/camera2/StreamConfigurationMap.java
deleted file mode 100644
index 5ddd7d6..0000000
--- a/core/java/android/hardware/camera2/StreamConfigurationMap.java
+++ /dev/null
@@ -1,508 +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 android.hardware.camera2;
-
-import android.graphics.ImageFormat;
-import android.graphics.PixelFormat;
-import android.hardware.camera2.utils.HashCodeHelpers;
-import android.view.Surface;
-import android.util.Size;
-
-import java.util.Arrays;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * Immutable class to store the available stream
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS configurations} to be used
- * when configuring streams with {@link CameraDevice#configureOutputs}.
- * <!-- TODO: link to input stream configuration -->
- *
- * <p>This is the authoritative list for all <!-- input/ -->output formats (and sizes respectively
- * for that format) that are supported by a camera device.</p>
- *
- * <p>This also contains the minimum frame durations and stall durations for each format/size
- * combination that can be used to calculate effective frame rate when submitting multiple captures.
- * </p>
- *
- * <p>An instance of this object is available from {@link CameraCharacteristics} using
- * the {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS} key and the
- * {@link CameraCharacteristics#get} method.</p.
- *
- * <pre>{@code
- * CameraCharacteristics characteristics = ...;
- * StreamConfigurationMap configs = characteristics.get(
- * CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
- * }</pre>
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
- * @see CameraDevice#configureOutputs
- */
-public final class StreamConfigurationMap {
-
- /**
- * Create a new {@link StreamConfigurationMap}.
- *
- * <p>The array parameters ownership is passed to this object after creation; do not
- * write to them after this constructor is invoked.</p>
- *
- * @param configurations a non-{@code null} array of {@link StreamConfiguration}
- * @param durations a non-{@code null} array of {@link StreamConfigurationDuration}
- *
- * @throws NullPointerException if any of the arguments or subelements were {@code null}
- *
- * @hide
- */
- public StreamConfigurationMap(
- StreamConfiguration[] configurations,
- StreamConfigurationDuration[] durations) {
- // TODO: format check against ImageFormat/PixelFormat ?
-
- mConfigurations = checkArrayElementsNotNull(configurations, "configurations");
- mDurations = checkArrayElementsNotNull(durations, "durations");
-
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Get the image {@code format} output formats in this stream configuration.
- *
- * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
- * or in {@link PixelFormat} (and there is no possibility of collision).</p>
- *
- * <p>Formats listed in this array are guaranteed to return true if queried with
- * {@link #isOutputSupportedFor(int).</p>
- *
- * @return an array of integer format
- *
- * @see ImageFormat
- * @see PixelFormat
- */
- public final int[] getOutputFormats() {
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Get the image {@code format} input formats in this stream configuration.
- *
- * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
- * or in {@link PixelFormat} (and there is no possibility of collision).</p>
- *
- * @return an array of integer format
- *
- * @see ImageFormat
- * @see PixelFormat
- *
- * @hide
- */
- public final int[] getInputFormats() {
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Get the supported input sizes for this input format.
- *
- * <p>The format must have come from {@link #getInputFormats}; otherwise
- * {@code null} is returned.</p>
- *
- * @param format a format from {@link #getInputFormats}
- * @return a non-empty array of sizes, or {@code null} if the format was not available.
- *
- * @hide
- */
- public Size[] getInputSizes(final int format) {
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Determine whether or not output streams can be
- * {@link CameraDevice#configureOutputs configured} with a particular user-defined format.
- *
- * <p>This method determines that the output {@code format} is supported by the camera device;
- * each output {@code surface} target may or may not itself support that {@code format}.
- * Refer to the class which provides the surface for additional documentation.</p>
- *
- * <p>Formats for which this returns {@code true} are guaranteed to exist in the result
- * returned by {@link #getOutputSizes}.</p>
- *
- * @param format an image format from either {@link ImageFormat} or {@link PixelFormat}
- * @return
- * {@code true} iff using a {@code surface} with this {@code format} will be
- * supported with {@link CameraDevice#configureOutputs}
- *
- * @throws IllegalArgumentException
- * if the image format was not a defined named constant
- * from either {@link ImageFormat} or {@link PixelFormat}
- *
- * @see ImageFormat
- * @see PixelFormat
- * @see CameraDevice#configureOutputs
- */
- public boolean isOutputSupportedFor(int format) {
- checkArgumentFormat(format);
-
- final int[] formats = getOutputFormats();
- for (int i = 0; i < formats.length; ++i) {
- if (format == formats[i]) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Determine whether or not output streams can be configured with a particular class
- * as a consumer.
- *
- * <p>The following list is generally usable for outputs:
- * <ul>
- * <li>{@link android.media.ImageReader} -
- * Recommended for image processing or streaming to external resources (such as a file or
- * network)
- * <li>{@link android.media.MediaRecorder} -
- * Recommended for recording video (simple to use)
- * <li>{@link android.media.MediaCodec} -
- * Recommended for recording video (more complicated to use, with more flexibility)
- * <li>{@link android.renderscript.Allocation} -
- * Recommended for image processing with {@link android.renderscript RenderScript}
- * <li>{@link android.view.SurfaceHolder} -
- * Recommended for low-power camera preview with {@link android.view.SurfaceView}
- * <li>{@link android.graphics.SurfaceTexture} -
- * Recommended for OpenGL-accelerated preview processing or compositing with
- * {@link android.view.TextureView}
- * </ul>
- * </p>
- *
- * <p>Generally speaking this means that creating a {@link Surface} from that class <i>may</i>
- * provide a producer endpoint that is suitable to be used with
- * {@link CameraDevice#configureOutputs}.</p>
- *
- * <p>Since not all of the above classes support output of all format and size combinations,
- * the particular combination should be queried with {@link #isOutputSupportedFor(Surface)}.</p>
- *
- * @param klass a non-{@code null} {@link Class} object reference
- * @return {@code true} if this class is supported as an output, {@code false} otherwise
- *
- * @throws NullPointerException if {@code klass} was {@code null}
- *
- * @see CameraDevice#configureOutputs
- * @see #isOutputSupportedFor(Surface)
- */
- public static <T> boolean isOutputSupportedFor(final Class<T> klass) {
- checkNotNull(klass, "klass must not be null");
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Determine whether or not the {@code surface} in its current state is suitable to be
- * {@link CameraDevice#configureOutputs configured} as an output.
- *
- * <p>Not all surfaces are usable with the {@link CameraDevice}, and not all configurations
- * of that {@code surface} are compatible. Some classes that provide the {@code surface} are
- * compatible with the {@link CameraDevice} in general
- * (see {@link #isOutputSupportedFor(Class)}, but it is the caller's responsibility to put the
- * {@code surface} into a state that will be compatible with the {@link CameraDevice}.</p>
- *
- * <p>Reasons for a {@code surface} being specifically incompatible might be:
- * <ul>
- * <li>Using a format that's not listed by {@link #getOutputFormats}
- * <li>Using a format/size combination that's not listed by {@link #getOutputSizes}
- * <li>The {@code surface} itself is not in a state where it can service a new producer.</p>
- * </li>
- * </ul>
- *
- * This is not an exhaustive list; see the particular class's documentation for further
- * possible reasons of incompatibility.</p>
- *
- * @param surface a non-{@code null} {@link Surface} object reference
- * @return {@code true} if this is supported, {@code false} otherwise
- *
- * @throws NullPointerException if {@code surface} was {@code null}
- *
- * @see CameraDevice#configureOutputs
- * @see #isOutputSupportedFor(Class)
- */
- public boolean isOutputSupportedFor(final Surface surface) {
- checkNotNull(surface, "surface must not be null");
-
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Get a list of sizes compatible with {@code klass} to use as an output.
- *
- * <p>Since some of the supported classes may support additional formats beyond
- * an opaque/implementation-defined (under-the-hood) format; this function only returns
- * sizes for the implementation-defined format.</p>
- *
- * <p>Some classes such as {@link android.media.ImageReader} may only support user-defined
- * formats; in particular {@link #isOutputSupportedFor(Class)} will return {@code true} for
- * that class and this method will return an empty array (but not {@code null}).</p>
- *
- * <p>If a well-defined format such as {@code NV21} is required, use
- * {@link #getOutputSizes(int)} instead.</p>
- *
- * <p>The {@code klass} should be a supported output, that querying
- * {@code #isOutputSupportedFor(Class)} should return {@code true}.</p>
- *
- * @param klass
- * a non-{@code null} {@link Class} object reference
- * @return
- * an array of supported sizes for implementation-defined formats,
- * or {@code null} iff the {@code klass} is not a supported output
- *
- * @throws NullPointerException if {@code klass} was {@code null}
- *
- * @see #isOutputSupportedFor(Class)
- */
- public <T> Size[] getOutputSizes(final Class<T> klass) {
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Get a list of sizes compatible with the requested image {@code format}.
- *
- * <p>The {@code format} should be a supported format (one of the formats returned by
- * {@link #getOutputFormats}).</p>
- *
- * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
- * @return
- * an array of supported sizes,
- * or {@code null} if the {@code format} is not a supported output
- *
- * @see ImageFormat
- * @see PixelFormat
- * @see #getOutputFormats
- */
- public Size[] getOutputSizes(final int format) {
- try {
- checkArgumentFormatSupported(format, /*output*/true);
- } catch (IllegalArgumentException e) {
- return null;
- }
-
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
- * for the format/size combination (in nanoseconds).
- *
- * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p>
- * <p>{@code size} should be one of the ones returned by
- * {@link #getOutputSizes(int)}.</p>
- *
- * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
- * @param size an output-compatible size
- * @return a minimum frame duration {@code >=} 0 in nanoseconds
- *
- * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
- * @throws NullPointerException if {@code size} was {@code null}
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
- * @see CaptureRequest#SENSOR_FRAME_DURATION
- * @see ImageFormat
- * @see PixelFormat
- */
- public long getOutputMinFrameDuration(final int format, final Size size) {
- checkArgumentFormatSupported(format, /*output*/true);
-
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
- * for the class/size combination (in nanoseconds).
- *
- * <p>This assumes a the {@code klass} is set up to use an implementation-defined format.
- * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p>
- *
- * <p>{@code klass} should be one of the ones which is supported by
- * {@link #isOutputSupportedFor(Class)}.</p>
- *
- * <p>{@code size} should be one of the ones returned by
- * {@link #getOutputSizes(int)}.</p>
- *
- * @param klass
- * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a
- * non-empty array returned by {@link #getOutputSizes(Class)}
- * @param size an output-compatible size
- * @return a minimum frame duration {@code >=} 0 in nanoseconds
- *
- * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
- * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
- * @see CaptureRequest#SENSOR_FRAME_DURATION
- * @see ImageFormat
- * @see PixelFormat
- */
- public <T> long getOutputMinFrameDuration(final Class<T> klass, final Size size) {
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Get the {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS stall duration}
- * for the format/size combination (in nanoseconds).
- *
- * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p>
- * <p>{@code size} should be one of the ones returned by
- * {@link #getOutputSizes(int)}.</p>
- *
- * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
- * @param size an output-compatible size
- * @return a stall duration {@code >=} 0 in nanoseconds
- *
- * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
- * @throws NullPointerException if {@code size} was {@code null}
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
- * @see ImageFormat
- * @see PixelFormat
- */
- public long getOutputStallDuration(final int format, final Size size) {
- checkArgumentFormatSupported(format, /*output*/true);
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Get the {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS stall duration}
- * for the class/size combination (in nanoseconds).
- *
- * <p>This assumes a the {@code klass} is set up to use an implementation-defined format.
- * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p>
- *
- * <p>{@code klass} should be one of the ones with a non-empty array returned by
- * {@link #getOutputSizes(Class)}.</p>
- *
- * <p>{@code size} should be one of the ones returned by
- * {@link #getOutputSizes(Class)}.</p>
- *
- * @param klass
- * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a
- * non-empty array returned by {@link #getOutputSizes(Class)}
- * @param size an output-compatible size
- * @return a minimum frame duration {@code >=} 0 in nanoseconds
- *
- * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
- * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
- * @see CaptureRequest#SENSOR_FRAME_DURATION
- * @see ImageFormat
- * @see PixelFormat
- */
- public <T> long getOutputStallDuration(final Class<T> klass, final Size size) {
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Check if this {@link StreamConfigurationMap} is equal to another
- * {@link StreamConfigurationMap}.
- *
- * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
- *
- * @return {@code true} if the objects were equal, {@code false} otherwise
- */
- @Override
- public boolean equals(final Object obj) {
- if (obj == null) {
- return false;
- }
- if (this == obj) {
- return true;
- }
- if (obj instanceof StreamConfigurationMap) {
- final StreamConfigurationMap other = (StreamConfigurationMap) obj;
- // TODO: do we care about order?
- return Arrays.equals(mConfigurations, other.mConfigurations) &&
- Arrays.equals(mDurations, other.mDurations);
- }
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- // TODO: do we care about order?
- return HashCodeHelpers.hashCode(mConfigurations) ^ HashCodeHelpers.hashCode(mDurations);
- }
-
- // Check that the argument is supported by #getOutputFormats or #getInputFormats
- private int checkArgumentFormatSupported(int format, boolean output) {
- checkArgumentFormat(format);
-
- int[] formats = output ? getOutputFormats() : getInputFormats();
- for (int i = 0; i < formats.length; ++i) {
- if (format == formats[i]) {
- return format;
- }
- }
-
- throw new IllegalArgumentException(String.format(
- "format %x is not supported by this stream configuration map", format));
- }
-
- /**
- * Ensures that the format is either user-defined or implementation defined.
- *
- * <p>Any invalid/undefined formats will raise an exception.</p>
- *
- * @param format image format
- * @return the format
- *
- * @throws IllegalArgumentException if the format was invalid
- */
- static int checkArgumentFormatInternal(int format) {
- if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
- return format;
- }
-
- return checkArgumentFormat(format);
- }
-
- /**
- * Ensures that the format is user-defined in either ImageFormat or PixelFormat.
- *
- * <p>Any invalid/undefined formats will raise an exception, including implementation-defined.
- * </p>
- *
- * <p>Note that {@code @hide} and deprecated formats will not pass this check.</p>
- *
- * @param format image format
- * @return the format
- *
- * @throws IllegalArgumentException if the format was not user-defined
- */
- static int checkArgumentFormat(int format) {
- if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
- throw new IllegalArgumentException(String.format(
- "format %x was not defined in either ImageFormat or PixelFormat", format));
- }
-
- return format;
- }
-
- private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;
-
- private final StreamConfiguration[] mConfigurations;
- private final StreamConfigurationDuration[] mDurations;
-
-}
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index 988f8f9..628d1c3 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -24,9 +24,9 @@ import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.CaptureResultExtras;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
-import android.hardware.camera2.LongParcelable;
import android.hardware.camera2.utils.CameraBinderDecorator;
import android.hardware.camera2.utils.CameraRuntimeException;
+import android.hardware.camera2.utils.LongParcelable;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 9a06e97..d28f7bd 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -43,6 +43,9 @@ import android.hardware.camera2.marshal.impl.MarshalQueryableSizeF;
import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration;
import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration;
import android.hardware.camera2.marshal.impl.MarshalQueryableString;
+import android.hardware.camera2.params.StreamConfiguration;
+import android.hardware.camera2.params.StreamConfigurationDuration;
+import android.hardware.camera2.params.StreamConfigurationMap;
import android.os.Parcelable;
import android.os.Parcel;
import android.util.Log;
@@ -207,10 +210,8 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable {
return (T) getFaces();
} else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) {
return (T) getFaceRectangles();
- } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS)) {
- return (T) getAvailableStreamConfigurations();
- } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS)) {
- return (T) getAvailableMinFrameDurations();
+ } else if (key.equals(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)) {
+ return (T) getStreamConfigurationMap();
}
// For other keys, get() falls back to getBase()
@@ -231,50 +232,6 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable {
return availableFormats;
}
- private int[] getAvailableStreamConfigurations() {
- final int NUM_ELEMENTS_IN_CONFIG = 4;
- int[] availableConfigs =
- getBase(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
- if (availableConfigs != null) {
- if (availableConfigs.length % NUM_ELEMENTS_IN_CONFIG != 0) {
- Log.w(TAG, "availableStreamConfigurations is malformed, length must be multiple"
- + " of " + NUM_ELEMENTS_IN_CONFIG);
- return availableConfigs;
- }
-
- for (int i = 0; i < availableConfigs.length; i += NUM_ELEMENTS_IN_CONFIG) {
- // JPEG has different value between native and managed side, need override.
- if (availableConfigs[i] == NATIVE_JPEG_FORMAT) {
- availableConfigs[i] = ImageFormat.JPEG;
- }
- }
- }
-
- return availableConfigs;
- }
-
- private long[] getAvailableMinFrameDurations() {
- final int NUM_ELEMENTS_IN_DURATION = 4;
- long[] availableMinDurations =
- getBase(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
- if (availableMinDurations != null) {
- if (availableMinDurations.length % NUM_ELEMENTS_IN_DURATION != 0) {
- Log.w(TAG, "availableStreamConfigurations is malformed, length must be multiple"
- + " of " + NUM_ELEMENTS_IN_DURATION);
- return availableMinDurations;
- }
-
- for (int i = 0; i < availableMinDurations.length; i += NUM_ELEMENTS_IN_DURATION) {
- // JPEG has different value between native and managed side, need override.
- if (availableMinDurations[i] == NATIVE_JPEG_FORMAT) {
- availableMinDurations[i] = ImageFormat.JPEG;
- }
- }
- }
-
- return availableMinDurations;
- }
-
private Face[] getFaces() {
final int FACE_LANDMARK_SIZE = 6;
@@ -374,6 +331,17 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable {
return fixedFaceRectangles;
}
+ private StreamConfigurationMap getStreamConfigurationMap() {
+ StreamConfiguration[] configurations = getBase(
+ CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+ StreamConfigurationDuration[] minFrameDurations = getBase(
+ CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
+ StreamConfigurationDuration[] stallDurations = getBase(
+ CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS);
+
+ return new StreamConfigurationMap(configurations, minFrameDurations, stallDurations);
+ }
+
private <T> void setBase(Key<T> key, T value) {
int tag = key.getTag();
@@ -401,56 +369,12 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable {
return setAvailableFormats((int[]) value);
} else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) {
return setFaceRectangles((Rect[]) value);
- } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS)) {
- return setAvailableStreamConfigurations((int[])value);
- } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS)) {
- return setAvailableMinFrameDurations((long[])value);
}
// For other keys, set() falls back to setBase().
return false;
}
- private boolean setAvailableStreamConfigurations(int[] value) {
- final int NUM_ELEMENTS_IN_CONFIG = 4;
- int[] availableConfigs = value;
- if (value == null) {
- // Let setBase() to handle the null value case.
- return false;
- }
-
- int[] newValues = new int[availableConfigs.length];
- for (int i = 0; i < availableConfigs.length; i++) {
- newValues[i] = availableConfigs[i];
- if (i % NUM_ELEMENTS_IN_CONFIG == 0 && availableConfigs[i] == ImageFormat.JPEG) {
- newValues[i] = NATIVE_JPEG_FORMAT;
- }
- }
-
- setBase(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS, newValues);
- return true;
- }
-
- private boolean setAvailableMinFrameDurations(long[] value) {
- final int NUM_ELEMENTS_IN_DURATION = 4;
- long[] availableDurations = value;
- if (value == null) {
- // Let setBase() to handle the null value case.
- return false;
- }
-
- long[] newValues = new long[availableDurations.length];
- for (int i = 0; i < availableDurations.length; i++) {
- newValues[i] = availableDurations[i];
- if (i % NUM_ELEMENTS_IN_DURATION == 0 && availableDurations[i] == ImageFormat.JPEG) {
- newValues[i] = NATIVE_JPEG_FORMAT;
- }
- }
-
- setBase(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS, newValues);
- return true;
- }
-
private boolean setAvailableFormats(int[] value) {
int[] availableFormat = value;
if (value == null) {
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableReprocessFormatsMap.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableReprocessFormatsMap.java
index 3025cb4..98a7ad7 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableReprocessFormatsMap.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableReprocessFormatsMap.java
@@ -15,9 +15,10 @@
*/
package android.hardware.camera2.marshal.impl;
-import android.hardware.camera2.ReprocessFormatsMap;
import android.hardware.camera2.marshal.Marshaler;
import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.ReprocessFormatsMap;
+import android.hardware.camera2.params.StreamConfigurationMap;
import android.hardware.camera2.utils.TypeReference;
import static android.hardware.camera2.impl.CameraMetadataNative.*;
@@ -50,12 +51,13 @@ public class MarshalQueryableReprocessFormatsMap
* INPUT_FORMAT, OUTPUT_FORMAT_COUNT, [OUTPUT_0, OUTPUT_1, ..., OUTPUT_FORMAT_COUNT-1]
* };
*/
- int[] inputs = value.getInputs();
+ int[] inputs = StreamConfigurationMap.imageFormatToInternal(value.getInputs());
for (int input : inputs) {
// INPUT_FORMAT
buffer.putInt(input);
- int[] outputs = value.getOutputs(input);
+ int[] outputs =
+ StreamConfigurationMap.imageFormatToInternal(value.getOutputs(input));
// OUTPUT_FORMAT_COUNT
buffer.putInt(outputs.length);
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfiguration.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfiguration.java
index 6a4e821..62ace31 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfiguration.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfiguration.java
@@ -15,9 +15,9 @@
*/
package android.hardware.camera2.marshal.impl;
-import android.hardware.camera2.StreamConfiguration;
import android.hardware.camera2.marshal.Marshaler;
import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.StreamConfiguration;
import android.hardware.camera2.utils.TypeReference;
import static android.hardware.camera2.impl.CameraMetadataNative.*;
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfigurationDuration.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfigurationDuration.java
index c3d564e..fd3dfac 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfigurationDuration.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfigurationDuration.java
@@ -15,9 +15,9 @@
*/
package android.hardware.camera2.marshal.impl;
-import android.hardware.camera2.StreamConfigurationDuration;
import android.hardware.camera2.marshal.Marshaler;
import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.StreamConfigurationDuration;
import android.hardware.camera2.utils.TypeReference;
import static android.hardware.camera2.impl.CameraMetadataNative.*;
diff --git a/core/java/android/hardware/camera2/ReprocessFormatsMap.java b/core/java/android/hardware/camera2/params/ReprocessFormatsMap.java
index 894a499..d3f5bc3 100644
--- a/core/java/android/hardware/camera2/ReprocessFormatsMap.java
+++ b/core/java/android/hardware/camera2/params/ReprocessFormatsMap.java
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package android.hardware.camera2;
+package android.hardware.camera2.params;
import static com.android.internal.util.Preconditions.*;
+import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.utils.HashCodeHelpers;
import java.util.Arrays;
@@ -61,9 +62,12 @@ public final class ReprocessFormatsMap {
* @throws IllegalArgumentException
* if the data was poorly formatted
* (missing output format length or too few output formats)
+ * or if any of the input/formats were not valid
* @throws NullPointerException
* if entry was null
*
+ * @see StreamConfigurationMap#checkArgumentFormatInternal
+ *
* @hide
*/
public ReprocessFormatsMap(final int[] entry) {
@@ -72,26 +76,31 @@ public final class ReprocessFormatsMap {
int numInputs = 0;
int left = entry.length;
for (int i = 0; i < entry.length; ) {
- final int format = entry[i];
+ int inputFormat = StreamConfigurationMap.checkArgumentFormatInternal(entry[i]);
left--;
i++;
if (left < 1) {
throw new IllegalArgumentException(
- String.format("Input %x had no output format length listed", format));
+ String.format("Input %x had no output format length listed", inputFormat));
}
final int length = entry[i];
left--;
i++;
+ for (int j = 0; j < length; ++j) {
+ int outputFormat = entry[i + j];
+ StreamConfigurationMap.checkArgumentFormatInternal(outputFormat);
+ }
+
if (length > 0) {
if (left < length) {
throw new IllegalArgumentException(
String.format(
"Input %x had too few output formats listed (actual: %d, " +
- "expected: %d)", format, left, length));
+ "expected: %d)", inputFormat, left, length));
}
i += length;
@@ -131,7 +140,6 @@ public final class ReprocessFormatsMap {
throw new AssertionError(
String.format("Input %x had no output format length listed", format));
}
- // TODO: check format is a valid input format
final int length = mEntry[i];
left--;
@@ -149,12 +157,10 @@ public final class ReprocessFormatsMap {
left -= length;
}
- // TODO: check output format is a valid output format
-
inputs[j] = format;
}
- return inputs;
+ return StreamConfigurationMap.imageFormatToPublic(inputs);
}
/**
@@ -204,7 +210,7 @@ public final class ReprocessFormatsMap {
outputs[k] = mEntry[i + k];
}
- return outputs;
+ return StreamConfigurationMap.imageFormatToPublic(outputs);
}
i += length;
diff --git a/core/java/android/hardware/camera2/StreamConfiguration.java b/core/java/android/hardware/camera2/params/StreamConfiguration.java
index a514034..1c6b6e9 100644
--- a/core/java/android/hardware/camera2/StreamConfiguration.java
+++ b/core/java/android/hardware/camera2/params/StreamConfiguration.java
@@ -14,13 +14,16 @@
* limitations under the License.
*/
-package android.hardware.camera2;
+package android.hardware.camera2.params;
import static com.android.internal.util.Preconditions.*;
-import static android.hardware.camera2.StreamConfigurationMap.checkArgumentFormatInternal;
+import static android.hardware.camera2.params.StreamConfigurationMap.checkArgumentFormatInternal;
import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.utils.HashCodeHelpers;
+import android.graphics.PixelFormat;
import android.util.Size;
/**
@@ -62,11 +65,12 @@ public final class StreamConfiguration {
}
/**
- * Get the image {@code format} in this stream configuration.
+ * Get the internal image {@code format} in this stream configuration.
*
* @return an integer format
*
* @see ImageFormat
+ * @see PixelFormat
*/
public final int getFormat() {
return mFormat;
diff --git a/core/java/android/hardware/camera2/StreamConfigurationDuration.java b/core/java/android/hardware/camera2/params/StreamConfigurationDuration.java
index 6a31156..217059d 100644
--- a/core/java/android/hardware/camera2/StreamConfigurationDuration.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationDuration.java
@@ -14,13 +14,15 @@
* limitations under the License.
*/
-package android.hardware.camera2;
+package android.hardware.camera2.params;
import static com.android.internal.util.Preconditions.*;
-import static android.hardware.camera2.StreamConfigurationMap.checkArgumentFormatInternal;
+import static android.hardware.camera2.params.StreamConfigurationMap.checkArgumentFormatInternal;
import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.utils.HashCodeHelpers;
+import android.graphics.PixelFormat;
import android.util.Size;
/**
@@ -59,11 +61,12 @@ public final class StreamConfigurationDuration {
}
/**
- * Get the image {@code format} in this stream configuration duration
+ * Get the internal image {@code format} in this stream configuration duration
*
* @return an integer format
*
* @see ImageFormat
+ * @see PixelFormat
*/
public final int getFormat() {
return mFormat;
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
new file mode 100644
index 0000000..4cd6d15
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -0,0 +1,949 @@
+/*
+ * 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.hardware.camera2.params;
+
+import android.graphics.ImageFormat;
+import android.graphics.PixelFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.utils.HashCodeHelpers;
+import android.view.Surface;
+import android.util.Log;
+import android.util.Size;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Objects;
+
+import static com.android.internal.util.Preconditions.*;
+
+/**
+ * Immutable class to store the available stream
+ * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP configurations} to be used
+ * when configuring streams with {@link CameraDevice#configureOutputs}.
+ * <!-- TODO: link to input stream configuration -->
+ *
+ * <p>This is the authoritative list for all <!-- input/ -->output formats (and sizes respectively
+ * for that format) that are supported by a camera device.</p>
+ *
+ * <p>This also contains the minimum frame durations and stall durations for each format/size
+ * combination that can be used to calculate effective frame rate when submitting multiple captures.
+ * </p>
+ *
+ * <p>An instance of this object is available from {@link CameraCharacteristics} using
+ * the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP} key and the
+ * {@link CameraCharacteristics#get} method.</p>
+ *
+ * <pre><code>{@code
+ * CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
+ * StreamConfigurationMap configs = characteristics.get(
+ * CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ * }</code></pre>
+ *
+ * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
+ * @see CameraDevice#configureOutputs
+ */
+public final class StreamConfigurationMap {
+
+ private static final String TAG = "StreamConfigurationMap";
+ /**
+ * Create a new {@link StreamConfigurationMap}.
+ *
+ * <p>The array parameters ownership is passed to this object after creation; do not
+ * write to them after this constructor is invoked.</p>
+ *
+ * @param configurations a non-{@code null} array of {@link StreamConfiguration}
+ * @param minFrameDurations a non-{@code null} array of {@link StreamConfigurationDuration}
+ * @param stallDurations a non-{@code null} array of {@link StreamConfigurationDuration}
+ *
+ * @throws NullPointerException if any of the arguments or subelements were {@code null}
+ *
+ * @hide
+ */
+ public StreamConfigurationMap(
+ StreamConfiguration[] configurations,
+ StreamConfigurationDuration[] minFrameDurations,
+ StreamConfigurationDuration[] stallDurations) {
+
+ mConfigurations = checkArrayElementsNotNull(configurations, "configurations");
+ mMinFrameDurations = checkArrayElementsNotNull(minFrameDurations, "minFrameDurations");
+ mStallDurations = checkArrayElementsNotNull(stallDurations, "stallDurations");
+
+ // For each format, track how many sizes there are available to configure
+ for (StreamConfiguration config : configurations) {
+ HashMap<Integer, Integer> map = config.isOutput() ? mOutputFormats : mInputFormats;
+
+ Integer count = map.get(config.getFormat());
+
+ if (count == null) {
+ count = 0;
+ }
+ count = count + 1;
+
+ map.put(config.getFormat(), count);
+ }
+
+ if (!mOutputFormats.containsKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)) {
+ throw new AssertionError(
+ "At least one stream configuration for IMPLEMENTATION_DEFINED must exist");
+ }
+ }
+
+ /**
+ * Get the image {@code format} output formats in this stream configuration.
+ *
+ * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
+ * or in {@link PixelFormat} (and there is no possibility of collision).</p>
+ *
+ * <p>Formats listed in this array are guaranteed to return true if queried with
+ * {@link #isOutputSupportedFor(int).</p>
+ *
+ * @return an array of integer format
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ */
+ public final int[] getOutputFormats() {
+ return getPublicFormats(/*output*/true);
+ }
+
+ /**
+ * Get the image {@code format} input formats in this stream configuration.
+ *
+ * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
+ * or in {@link PixelFormat} (and there is no possibility of collision).</p>
+ *
+ * @return an array of integer format
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ *
+ * @hide
+ */
+ public final int[] getInputFormats() {
+ return getPublicFormats(/*output*/false);
+ }
+
+ /**
+ * Get the supported input sizes for this input format.
+ *
+ * <p>The format must have come from {@link #getInputFormats}; otherwise
+ * {@code null} is returned.</p>
+ *
+ * @param format a format from {@link #getInputFormats}
+ * @return a non-empty array of sizes, or {@code null} if the format was not available.
+ *
+ * @hide
+ */
+ public Size[] getInputSizes(final int format) {
+ return getPublicFormatSizes(format, /*output*/false);
+ }
+
+ /**
+ * Determine whether or not output streams can be
+ * {@link CameraDevice#configureOutputs configured} with a particular user-defined format.
+ *
+ * <p>This method determines that the output {@code format} is supported by the camera device;
+ * each output {@code surface} target may or may not itself support that {@code format}.
+ * Refer to the class which provides the surface for additional documentation.</p>
+ *
+ * <p>Formats for which this returns {@code true} are guaranteed to exist in the result
+ * returned by {@link #getOutputSizes}.</p>
+ *
+ * @param format an image format from either {@link ImageFormat} or {@link PixelFormat}
+ * @return
+ * {@code true} iff using a {@code surface} with this {@code format} will be
+ * supported with {@link CameraDevice#configureOutputs}
+ *
+ * @throws IllegalArgumentException
+ * if the image format was not a defined named constant
+ * from either {@link ImageFormat} or {@link PixelFormat}
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ * @see CameraDevice#configureOutputs
+ */
+ public boolean isOutputSupportedFor(int format) {
+ checkArgumentFormat(format);
+
+ format = imageFormatToInternal(format);
+ return getFormatsMap(/*output*/true).containsKey(format);
+ }
+
+ /**
+ * Determine whether or not output streams can be configured with a particular class
+ * as a consumer.
+ *
+ * <p>The following list is generally usable for outputs:
+ * <ul>
+ * <li>{@link android.media.ImageReader} -
+ * Recommended for image processing or streaming to external resources (such as a file or
+ * network)
+ * <li>{@link android.media.MediaRecorder} -
+ * Recommended for recording video (simple to use)
+ * <li>{@link android.media.MediaCodec} -
+ * Recommended for recording video (more complicated to use, with more flexibility)
+ * <li>{@link android.renderscript.Allocation} -
+ * Recommended for image processing with {@link android.renderscript RenderScript}
+ * <li>{@link android.view.SurfaceHolder} -
+ * Recommended for low-power camera preview with {@link android.view.SurfaceView}
+ * <li>{@link android.graphics.SurfaceTexture} -
+ * Recommended for OpenGL-accelerated preview processing or compositing with
+ * {@link android.view.TextureView}
+ * </ul>
+ * </p>
+ *
+ * <p>Generally speaking this means that creating a {@link Surface} from that class <i>may</i>
+ * provide a producer endpoint that is suitable to be used with
+ * {@link CameraDevice#configureOutputs}.</p>
+ *
+ * <p>Since not all of the above classes support output of all format and size combinations,
+ * the particular combination should be queried with {@link #isOutputSupportedFor(Surface)}.</p>
+ *
+ * @param klass a non-{@code null} {@link Class} object reference
+ * @return {@code true} if this class is supported as an output, {@code false} otherwise
+ *
+ * @throws NullPointerException if {@code klass} was {@code null}
+ *
+ * @see CameraDevice#configureOutputs
+ * @see #isOutputSupportedFor(Surface)
+ */
+ public static <T> boolean isOutputSupportedFor(Class<T> klass) {
+ checkNotNull(klass, "klass must not be null");
+
+ if (klass == android.media.ImageReader.class) {
+ return true;
+ } else if (klass == android.media.MediaRecorder.class) {
+ return true;
+ } else if (klass == android.media.MediaCodec.class) {
+ return true;
+ } else if (klass == android.renderscript.Allocation.class) {
+ return true;
+ } else if (klass == android.view.SurfaceHolder.class) {
+ return true;
+ } else if (klass == android.graphics.SurfaceTexture.class) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Determine whether or not the {@code surface} in its current state is suitable to be
+ * {@link CameraDevice#configureOutputs configured} as an output.
+ *
+ * <p>Not all surfaces are usable with the {@link CameraDevice}, and not all configurations
+ * of that {@code surface} are compatible. Some classes that provide the {@code surface} are
+ * compatible with the {@link CameraDevice} in general
+ * (see {@link #isOutputSupportedFor(Class)}, but it is the caller's responsibility to put the
+ * {@code surface} into a state that will be compatible with the {@link CameraDevice}.</p>
+ *
+ * <p>Reasons for a {@code surface} being specifically incompatible might be:
+ * <ul>
+ * <li>Using a format that's not listed by {@link #getOutputFormats}
+ * <li>Using a format/size combination that's not listed by {@link #getOutputSizes}
+ * <li>The {@code surface} itself is not in a state where it can service a new producer.</p>
+ * </li>
+ * </ul>
+ *
+ * This is not an exhaustive list; see the particular class's documentation for further
+ * possible reasons of incompatibility.</p>
+ *
+ * @param surface a non-{@code null} {@link Surface} object reference
+ * @return {@code true} if this is supported, {@code false} otherwise
+ *
+ * @throws NullPointerException if {@code surface} was {@code null}
+ *
+ * @see CameraDevice#configureOutputs
+ * @see #isOutputSupportedFor(Class)
+ */
+ public boolean isOutputSupportedFor(Surface surface) {
+ checkNotNull(surface, "surface must not be null");
+
+ throw new UnsupportedOperationException("Not implemented yet");
+
+ // TODO: JNI function that checks the Surface's IGraphicBufferProducer state
+ }
+
+ /**
+ * Get a list of sizes compatible with {@code klass} to use as an output.
+ *
+ * <p>Since some of the supported classes may support additional formats beyond
+ * an opaque/implementation-defined (under-the-hood) format; this function only returns
+ * sizes for the implementation-defined format.</p>
+ *
+ * <p>Some classes such as {@link android.media.ImageReader} may only support user-defined
+ * formats; in particular {@link #isOutputSupportedFor(Class)} will return {@code true} for
+ * that class and this method will return an empty array (but not {@code null}).</p>
+ *
+ * <p>If a well-defined format such as {@code NV21} is required, use
+ * {@link #getOutputSizes(int)} instead.</p>
+ *
+ * <p>The {@code klass} should be a supported output, that querying
+ * {@code #isOutputSupportedFor(Class)} should return {@code true}.</p>
+ *
+ * @param klass
+ * a non-{@code null} {@link Class} object reference
+ * @return
+ * an array of supported sizes for implementation-defined formats,
+ * or {@code null} iff the {@code klass} is not a supported output
+ *
+ * @throws NullPointerException if {@code klass} was {@code null}
+ *
+ * @see #isOutputSupportedFor(Class)
+ */
+ public <T> Size[] getOutputSizes(Class<T> klass) {
+ if (isOutputSupportedFor(klass) == false) {
+ return null;
+ }
+
+ return getInternalFormatSizes(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, /*output*/true);
+ }
+
+ /**
+ * Get a list of sizes compatible with the requested image {@code format}.
+ *
+ * <p>The {@code format} should be a supported format (one of the formats returned by
+ * {@link #getOutputFormats}).</p>
+ *
+ * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+ * @return
+ * an array of supported sizes,
+ * or {@code null} if the {@code format} is not a supported output
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ * @see #getOutputFormats
+ */
+ public Size[] getOutputSizes(int format) {
+ return getPublicFormatSizes(format, /*output*/true);
+ }
+
+ /**
+ * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
+ * for the format/size combination (in nanoseconds).
+ *
+ * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p>
+ * <p>{@code size} should be one of the ones returned by
+ * {@link #getOutputSizes(int)}.</p>
+ *
+ * <p>This should correspond to the frame duration when only that stream is active, with all
+ * processing (typically in {@code android.*.mode}) set to either {@code OFF} or {@code FAST}.
+ * </p>
+ *
+ * <p>When multiple streams are used in a request, the minimum frame duration will be
+ * {@code max(individual stream min durations)}.</p>
+ *
+ * <!--
+ * TODO: uncomment after adding input stream support
+ * <p>The minimum frame duration of a stream (of a particular format, size) is the same
+ * regardless of whether the stream is input or output.</p>
+ * -->
+ *
+ * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+ * @param size an output-compatible size
+ * @return a minimum frame duration {@code >=} 0 in nanoseconds
+ *
+ * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} was {@code null}
+ *
+ * @see CaptureRequest#SENSOR_FRAME_DURATION
+ * @see #getOutputStallDuration(int, Size)
+ * @see ImageFormat
+ * @see PixelFormat
+ */
+ public long getOutputMinFrameDuration(int format, Size size) {
+ checkNotNull(size, "size must not be null");
+ checkArgumentFormatSupported(format, /*output*/true);
+
+ return getInternalFormatDuration(imageFormatToInternal(format), size, DURATION_MIN_FRAME);
+ }
+
+ /**
+ * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
+ * for the class/size combination (in nanoseconds).
+ *
+ * <p>This assumes a the {@code klass} is set up to use an implementation-defined format.
+ * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p>
+ *
+ * <p>{@code klass} should be one of the ones which is supported by
+ * {@link #isOutputSupportedFor(Class)}.</p>
+ *
+ * <p>{@code size} should be one of the ones returned by
+ * {@link #getOutputSizes(int)}.</p>
+ *
+ * <p>This should correspond to the frame duration when only that stream is active, with all
+ * processing (typically in {@code android.*.mode}) set to either {@code OFF} or {@code FAST}.
+ * </p>
+ *
+ * <p>When multiple streams are used in a request, the minimum frame duration will be
+ * {@code max(individual stream min durations)}.</p>
+ *
+ * <!--
+ * TODO: uncomment after adding input stream support
+ * <p>The minimum frame duration of a stream (of a particular format, size) is the same
+ * regardless of whether the stream is input or output.</p>
+ * -->
+ *
+ * @param klass
+ * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a
+ * non-empty array returned by {@link #getOutputSizes(Class)}
+ * @param size an output-compatible size
+ * @return a minimum frame duration {@code >=} 0 in nanoseconds
+ *
+ * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
+ *
+ * @see CaptureRequest#SENSOR_FRAME_DURATION
+ * @see ImageFormat
+ * @see PixelFormat
+ */
+ public <T> long getOutputMinFrameDuration(final Class<T> klass, final Size size) {
+ if (!isOutputSupportedFor(klass)) {
+ throw new IllegalArgumentException("klass was not supported");
+ }
+
+ return getInternalFormatDuration(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+ size, DURATION_MIN_FRAME);
+ }
+
+ /**
+ * Get the stall duration for the format/size combination (in nanoseconds).
+ *
+ * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p>
+ * <p>{@code size} should be one of the ones returned by
+ * {@link #getOutputSizes(int)}.</p>
+ *
+ * <p>
+ * A stall duration is how much extra time would get added to the normal minimum frame duration
+ * for a repeating request that has streams with non-zero stall.
+ *
+ * <p>For example, consider JPEG captures which have the following characteristics:
+ *
+ * <ul>
+ * <li>JPEG streams act like processed YUV streams in requests for which they are not included;
+ * in requests in which they are directly referenced, they act as JPEG streams.
+ * This is because supporting a JPEG stream requires the underlying YUV data to always be ready
+ * for use by a JPEG encoder, but the encoder will only be used (and impact frame duration) on
+ * requests that actually reference a JPEG stream.
+ * <li>The JPEG processor can run concurrently to the rest of the camera pipeline, but cannot
+ * process more than 1 capture at a time.
+ * </ul>
+ *
+ * <p>In other words, using a repeating YUV request would result in a steady frame rate
+ * (let's say it's 30 FPS). If a single JPEG request is submitted periodically,
+ * the frame rate will stay at 30 FPS (as long as we wait for the previous JPEG to return each
+ * time). If we try to submit a repeating YUV + JPEG request, then the frame rate will drop from
+ * 30 FPS.</p>
+ *
+ * <p>In general, submitting a new request with a non-0 stall time stream will <em>not</em> cause a
+ * frame rate drop unless there are still outstanding buffers for that stream from previous
+ * requests.</p>
+ *
+ * <p>Submitting a repeating request with streams (call this {@code S}) is the same as setting
+ * the minimum frame duration from the normal minimum frame duration corresponding to {@code S},
+ * added with the maximum stall duration for {@code S}.</p>
+ *
+ * <p>If interleaving requests with and without a stall duration, a request will stall by the
+ * maximum of the remaining times for each can-stall stream with outstanding buffers.</p>
+ *
+ * <p>This means that a stalling request will not have an exposure start until the stall has
+ * completed.</p>
+ *
+ * <p>This should correspond to the stall duration when only that stream is active, with all
+ * processing (typically in {@code android.*.mode}) set to {@code FAST} or {@code OFF}.
+ * Setting any of the processing modes to {@code HIGH_QUALITY} effectively results in an
+ * indeterminate stall duration for all streams in a request (the regular stall calculation
+ * rules are ignored).</p>
+ *
+ * <p>The following formats may always have a stall duration:
+ * <ul>
+ * <li>{@link ImageFormat#JPEG JPEG}
+ * <li>{@link ImageFormat#RAW_SENSOR RAW16}
+ * </ul>
+ * </p>
+ *
+ * <p>The following formats will never have a stall duration:
+ * <ul>
+ * <li>{@link ImageFormat#YUV_420_888 YUV_420_888}
+ * <li>{@link #isOutputSupportedFor(Class) Implementation-Defined}
+ * </ul></p>
+ *
+ * <p>
+ * All other formats may or may not have an allowed stall duration on a per-capability basis;
+ * refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * android.request.availableCapabilities} for more details.</p>
+ * </p>
+ *
+ * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration}
+ * for more information about calculating the max frame rate (absent stalls).</p>
+ *
+ * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+ * @param size an output-compatible size
+ * @return a stall duration {@code >=} 0 in nanoseconds
+ *
+ * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} was {@code null}
+ *
+ * @see CaptureRequest#SENSOR_FRAME_DURATION
+ * @see ImageFormat
+ * @see PixelFormat
+ */
+ public long getOutputStallDuration(int format, Size size) {
+ checkArgumentFormatSupported(format, /*output*/true);
+
+ return getInternalFormatDuration(imageFormatToInternal(format),
+ size, DURATION_STALL);
+ }
+
+ /**
+ * Get the stall duration for the class/size combination (in nanoseconds).
+ *
+ * <p>This assumes a the {@code klass} is set up to use an implementation-defined format.
+ * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p>
+ *
+ * <p>{@code klass} should be one of the ones with a non-empty array returned by
+ * {@link #getOutputSizes(Class)}.</p>
+ *
+ * <p>{@code size} should be one of the ones returned by
+ * {@link #getOutputSizes(Class)}.</p>
+ *
+ * <p>See {@link #getOutputStallDuration(int, Size)} for a definition of a
+ * <em>stall duration</em>.</p>
+ *
+ * @param klass
+ * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a
+ * non-empty array returned by {@link #getOutputSizes(Class)}
+ * @param size an output-compatible size
+ * @return a minimum frame duration {@code >=} 0 in nanoseconds
+ *
+ * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
+ *
+ * @see CaptureRequest#SENSOR_FRAME_DURATION
+ * @see ImageFormat
+ * @see PixelFormat
+ */
+ public <T> long getOutputStallDuration(final Class<T> klass, final Size size) {
+ if (!isOutputSupportedFor(klass)) {
+ throw new IllegalArgumentException("klass was not supported");
+ }
+
+ return getInternalFormatDuration(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+ size, DURATION_STALL);
+ }
+
+ /**
+ * Check if this {@link StreamConfigurationMap} is equal to another
+ * {@link StreamConfigurationMap}.
+ *
+ * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof StreamConfigurationMap) {
+ final StreamConfigurationMap other = (StreamConfigurationMap) obj;
+ // XX: do we care about order?
+ return Arrays.equals(mConfigurations, other.mConfigurations) &&
+ Arrays.equals(mMinFrameDurations, other.mMinFrameDurations) &&
+ Arrays.equals(mStallDurations, other.mStallDurations);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ // XX: do we care about order?
+ return HashCodeHelpers.hashCode(mConfigurations, mMinFrameDurations, mStallDurations);
+ }
+
+ // Check that the argument is supported by #getOutputFormats or #getInputFormats
+ private int checkArgumentFormatSupported(int format, boolean output) {
+ checkArgumentFormat(format);
+
+ int[] formats = output ? getOutputFormats() : getInputFormats();
+ for (int i = 0; i < formats.length; ++i) {
+ if (format == formats[i]) {
+ return format;
+ }
+ }
+
+ throw new IllegalArgumentException(String.format(
+ "format %x is not supported by this stream configuration map", format));
+ }
+
+ /**
+ * Ensures that the format is either user-defined or implementation defined.
+ *
+ * <p>If a format has a different internal representation than the public representation,
+ * passing in the public representation here will fail.</p>
+ *
+ * <p>For example if trying to use {@link ImageFormat#JPEG}:
+ * it has a different public representation than the internal representation
+ * {@code HAL_PIXEL_FORMAT_BLOB}, this check will fail.</p>
+ *
+ * <p>Any invalid/undefined formats will raise an exception.</p>
+ *
+ * @param format image format
+ * @return the format
+ *
+ * @throws IllegalArgumentException if the format was invalid
+ */
+ static int checkArgumentFormatInternal(int format) {
+ switch (format) {
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ case HAL_PIXEL_FORMAT_BLOB:
+ return format;
+ case ImageFormat.JPEG:
+ throw new IllegalArgumentException(
+ "ImageFormat.JPEG is an unknown internal format");
+ default:
+ return checkArgumentFormat(format);
+ }
+ }
+
+ /**
+ * Ensures that the format is publicly user-defined in either ImageFormat or PixelFormat.
+ *
+ * <p>If a format has a different public representation than the internal representation,
+ * passing in the internal representation here will fail.</p>
+ *
+ * <p>For example if trying to use {@code HAL_PIXEL_FORMAT_BLOB}:
+ * it has a different internal representation than the public representation
+ * {@link ImageFormat#JPEG}, this check will fail.</p>
+ *
+ * <p>Any invalid/undefined formats will raise an exception, including implementation-defined.
+ * </p>
+ *
+ * <p>Note that {@code @hide} and deprecated formats will not pass this check.</p>
+ *
+ * @param format image format
+ * @return the format
+ *
+ * @throws IllegalArgumentException if the format was not user-defined
+ */
+ static int checkArgumentFormat(int format) {
+ // TODO: remove this hack , CTS shouldn't have been using internal constants
+ if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
+ Log.w(TAG, "RAW_OPAQUE is not yet a published format; allowing it anyway");
+ return format;
+ }
+
+ if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
+ throw new IllegalArgumentException(String.format(
+ "format 0x%x was not defined in either ImageFormat or PixelFormat", format));
+ }
+
+ return format;
+ }
+
+ /**
+ * Convert a public-visible {@code ImageFormat} into an internal format
+ * compatible with {@code graphics.h}.
+ *
+ * <p>In particular these formats are converted:
+ * <ul>
+ * <li>HAL_PIXEL_FORMAT_BLOB => ImageFormat.JPEG
+ * </ul>
+ * </p>
+ *
+ * <p>Passing in an implementation-defined format which has no public equivalent will fail;
+ * as will passing in a public format which has a different internal format equivalent.
+ * See {@link #checkArgumentFormat} for more details about a legal public format.</p>
+ *
+ * <p>All other formats are returned as-is, no further invalid check is performed.</p>
+ *
+ * <p>This function is the dual of {@link #imageFormatToInternal}.</p>
+ *
+ * @param format image format from {@link ImageFormat} or {@link PixelFormat}
+ * @return the converted image formats
+ *
+ * @throws IllegalArgumentException
+ * if {@code format} is {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED} or
+ * {@link ImageFormat#JPEG}
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ * @see #checkArgumentFormat
+ */
+ static int imageFormatToPublic(int format) {
+ switch (format) {
+ case HAL_PIXEL_FORMAT_BLOB:
+ return ImageFormat.JPEG;
+ case ImageFormat.JPEG:
+ throw new IllegalArgumentException(
+ "ImageFormat.JPEG is an unknown internal format");
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ throw new IllegalArgumentException(
+ "IMPLEMENTATION_DEFINED must not leak to public API");
+ default:
+ return format;
+ }
+ }
+
+ /**
+ * Convert image formats from internal to public formats (in-place).
+ *
+ * @param formats an array of image formats
+ * @return {@code formats}
+ *
+ * @see #imageFormatToPublic
+ */
+ static int[] imageFormatToPublic(int[] formats) {
+ if (formats == null) {
+ return null;
+ }
+
+ for (int i = 0; i < formats.length; ++i) {
+ formats[i] = imageFormatToPublic(formats[i]);
+ }
+
+ return formats;
+ }
+
+ /**
+ * Convert a public format compatible with {@code ImageFormat} to an internal format
+ * from {@code graphics.h}.
+ *
+ * <p>In particular these formats are converted:
+ * <ul>
+ * <li>ImageFormat.JPEG => HAL_PIXEL_FORMAT_BLOB
+ * </ul>
+ * </p>
+ *
+ * <p>Passing in an implementation-defined format here will fail (it's not a public format);
+ * as will passing in an internal format which has a different public format equivalent.
+ * See {@link #checkArgumentFormat} for more details about a legal public format.</p>
+ *
+ * <p>All other formats are returned as-is, no invalid check is performed.</p>
+ *
+ * <p>This function is the dual of {@link #imageFormatToPublic}.</p>
+ *
+ * @param format public image format from {@link ImageFormat} or {@link PixelFormat}
+ * @return the converted image formats
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ *
+ * @throws IllegalArgumentException
+ * if {@code format} was {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED}
+ */
+ static int imageFormatToInternal(int format) {
+ switch (format) {
+ case ImageFormat.JPEG:
+ return HAL_PIXEL_FORMAT_BLOB;
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ throw new IllegalArgumentException(
+ "IMPLEMENTATION_DEFINED is not allowed via public API");
+ default:
+ return format;
+ }
+ }
+
+ /**
+ * Convert image formats from public to internal formats (in-place).
+ *
+ * @param formats an array of image formats
+ * @return {@code formats}
+ *
+ * @see #imageFormatToInternal
+ *
+ * @hide
+ */
+ public static int[] imageFormatToInternal(int[] formats) {
+ if (formats == null) {
+ return null;
+ }
+
+ for (int i = 0; i < formats.length; ++i) {
+ formats[i] = imageFormatToInternal(formats[i]);
+ }
+
+ return formats;
+ }
+
+ private Size[] getPublicFormatSizes(int format, boolean output) {
+ try {
+ checkArgumentFormatSupported(format, output);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+
+ format = imageFormatToInternal(format);
+
+ return getInternalFormatSizes(format, output);
+ }
+
+ private Size[] getInternalFormatSizes(int format, boolean output) {
+ HashMap<Integer, Integer> formatsMap = getFormatsMap(output);
+
+ Integer sizesCount = formatsMap.get(format);
+ if (sizesCount == null) {
+ throw new IllegalArgumentException("format not available");
+ }
+
+ int len = sizesCount;
+ Size[] sizes = new Size[len];
+ int sizeIndex = 0;
+
+ for (StreamConfiguration config : mConfigurations) {
+ if (config.getFormat() == format && config.isOutput() == output) {
+ sizes[sizeIndex++] = config.getSize();
+ }
+ }
+
+ if (sizeIndex != len) {
+ throw new AssertionError(
+ "Too few sizes (expected " + len + ", actual " + sizeIndex + ")");
+ }
+
+ return sizes;
+ }
+
+ /** Get the list of publically visible output formats; does not include IMPL_DEFINED */
+ private int[] getPublicFormats(boolean output) {
+ int[] formats = new int[getPublicFormatCount(output)];
+
+ int i = 0;
+
+ for (int format : getFormatsMap(output).keySet()) {
+ if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ formats[i++] = format;
+ }
+ }
+
+ if (formats.length != i) {
+ throw new AssertionError("Too few formats " + i + ", expected " + formats.length);
+ }
+
+ return imageFormatToPublic(formats);
+ }
+
+ /** Get the format -> size count map for either output or input formats */
+ private HashMap<Integer, Integer> getFormatsMap(boolean output) {
+ return output ? mOutputFormats : mInputFormats;
+ }
+
+ private long getInternalFormatDuration(int format, Size size, int duration) {
+ // assume format is already checked, since its internal
+
+ if (!arrayContains(getInternalFormatSizes(format, /*output*/true), size)) {
+ throw new IllegalArgumentException("size was not supported");
+ }
+
+ StreamConfigurationDuration[] durations = getDurations(duration);
+
+ for (StreamConfigurationDuration configurationDuration : durations) {
+ if (configurationDuration.getFormat() == format &&
+ configurationDuration.getWidth() == size.getWidth() &&
+ configurationDuration.getHeight() == size.getHeight()) {
+ return configurationDuration.getDuration();
+ }
+ }
+
+ return getDurationDefault(duration);
+ }
+
+ /**
+ * Get the durations array for the kind of duration
+ *
+ * @see #DURATION_MIN_FRAME
+ * @see #DURATION_STALL
+ * */
+ private StreamConfigurationDuration[] getDurations(int duration) {
+ switch (duration) {
+ case DURATION_MIN_FRAME:
+ return mMinFrameDurations;
+ case DURATION_STALL:
+ return mStallDurations;
+ default:
+ throw new IllegalArgumentException("duration was invalid");
+ }
+ }
+
+ private long getDurationDefault(int duration) {
+ switch (duration) {
+ case DURATION_MIN_FRAME:
+ throw new AssertionError("Minimum frame durations are required to be listed");
+ case DURATION_STALL:
+ return 0L; // OK. A lack of a stall duration implies a 0 stall duration
+ default:
+ throw new IllegalArgumentException("duration was invalid");
+ }
+ }
+
+ /** Count the number of publicly-visible output formats */
+ private int getPublicFormatCount(boolean output) {
+ HashMap<Integer, Integer> formatsMap = getFormatsMap(output);
+
+ int size = formatsMap.size();
+ if (formatsMap.containsKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)) {
+ size -= 1;
+ }
+ return size;
+ }
+
+ private static <T> boolean arrayContains(T[] array, T element) {
+ if (array == null) {
+ return false;
+ }
+
+ for (T el : array) {
+ if (Objects.equals(el, element)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // from system/core/include/system/graphics.h
+ private static final int HAL_PIXEL_FORMAT_BLOB = 0x21;
+ private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;
+ private static final int HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24;
+
+ /**
+ * @see #getDurations(int)
+ * @see #getDurationDefault(int)
+ */
+ private static final int DURATION_MIN_FRAME = 0;
+ private static final int DURATION_STALL = 1;
+
+ private final StreamConfiguration[] mConfigurations;
+ private final StreamConfigurationDuration[] mMinFrameDurations;
+ private final StreamConfigurationDuration[] mStallDurations;
+
+ /** ImageFormat -> num output sizes mapping */
+ private final HashMap</*ImageFormat*/Integer, /*Count*/Integer> mOutputFormats =
+ new HashMap<Integer, Integer>();
+ /** ImageFormat -> num input sizes mapping */
+ private final HashMap</*ImageFormat*/Integer, /*Count*/Integer> mInputFormats =
+ new HashMap<Integer, Integer>();
+
+}
diff --git a/core/java/android/hardware/camera2/LongParcelable.aidl b/core/java/android/hardware/camera2/utils/LongParcelable.aidl
index 7d7e51b..98ad1b2 100644
--- a/core/java/android/hardware/camera2/LongParcelable.aidl
+++ b/core/java/android/hardware/camera2/utils/LongParcelable.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.camera2;
+package android.hardware.camera2.utils;
/** @hide */
-parcelable LongParcelable; \ No newline at end of file
+parcelable LongParcelable;
diff --git a/core/java/android/hardware/camera2/LongParcelable.java b/core/java/android/hardware/camera2/utils/LongParcelable.java
index 97b0631..c89b339 100644
--- a/core/java/android/hardware/camera2/LongParcelable.java
+++ b/core/java/android/hardware/camera2/utils/LongParcelable.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.hardware.camera2;
+package android.hardware.camera2.utils;
import android.os.Parcel;
import android.os.Parcelable;
diff --git a/core/java/android/hardware/hdmi/HdmiCec.java b/core/java/android/hardware/hdmi/HdmiCec.java
index 7213c78..9193f89 100644
--- a/core/java/android/hardware/hdmi/HdmiCec.java
+++ b/core/java/android/hardware/hdmi/HdmiCec.java
@@ -120,7 +120,7 @@ public final class HdmiCec {
public static final int MESSAGE_TIMER_CLEARED_STATUS = 0x043;
public static final int MESSAGE_USER_CONTROL_PRESSED = 0x44;
public static final int MESSAGE_USER_CONTROL_RELEASED = 0x45;
- public static final int MESSAGE_GET_OSD_NAME = 0x46;
+ public static final int MESSAGE_GIVE_OSD_NAME = 0x46;
public static final int MESSAGE_SET_OSD_NAME = 0x47;
public static final int MESSAGE_SET_OSD_STRING = 0x64;
public static final int MESSAGE_SET_TIMER_PROGRAM_TITLE = 0x67;
@@ -158,6 +158,12 @@ public final class HdmiCec {
public static final int MESSAGE_VENDOR_COMMAND_WITH_ID = 0xA0;
public static final int MESSAGE_CLEAR_EXTERNAL_TIMER = 0xA1;
public static final int MESSAGE_SET_EXTERNAL_TIMER = 0xA2;
+ public static final int MESSAGE_INITIATE_ARC = 0xC0;
+ public static final int MESSAGE_REPORT_ARC_INITIATED = 0xC1;
+ public static final int MESSAGE_REPORT_ARC_TERMINATED = 0xC2;
+ public static final int MESSAGE_REQUEST_ARC_INITIATION = 0xC3;
+ public static final int MESSAGE_REQUEST_ARC_TERMINATION = 0xC4;
+ public static final int MESSAGE_TERMINATE_ARC = 0xC5;
public static final int MESSAGE_ABORT = 0xFF;
public static final int UNKNOWN_VENDOR_ID = 0xFFFFFF;
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 0a09fcb..489b8a5 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -89,7 +89,6 @@ public class LinkProperties implements Parcelable {
}
public LinkProperties() {
- clear();
}
// copy constructor instead of clone
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index f339e52..32050dc 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -146,9 +146,9 @@ public class BatteryManager {
return null;
}
- BatteryProperty prop = new BatteryProperty(Integer.MIN_VALUE);
+ BatteryProperty prop = new BatteryProperty();
if ((mBatteryPropertiesRegistrar.getProperty(id, prop) == 0) &&
- (prop.getInt() != Integer.MIN_VALUE))
+ (prop.getLong() != Long.MIN_VALUE))
return prop;
else
return null;
diff --git a/core/java/android/os/BatteryProperty.java b/core/java/android/os/BatteryProperty.java
index ec73952..0ed856e 100644
--- a/core/java/android/os/BatteryProperty.java
+++ b/core/java/android/os/BatteryProperty.java
@@ -53,20 +53,18 @@ public class BatteryProperty implements Parcelable {
*/
public static final int CAPACITY = 4;
- private int mValueInt;
-
/**
- * @hide
+ * Battery remaining energy in nanowatt-hours, as a long integer.
*/
- public BatteryProperty(int value) {
- mValueInt = value;
- }
+ public static final int ENERGY_COUNTER = 4;
+
+ private long mValueLong;
/**
* @hide
*/
public BatteryProperty() {
- mValueInt = Integer.MIN_VALUE;
+ mValueLong = Long.MIN_VALUE;
}
/**
@@ -79,9 +77,21 @@ public class BatteryProperty implements Parcelable {
* @return The queried property value, or Integer.MIN_VALUE if not supported.
*/
public int getInt() {
- return mValueInt;
+ return (int)mValueLong;
}
+ /**
+ * Return the value of a property of long type previously queried
+ * via {@link BatteryManager#getProperty
+ * BatteryManager.getProperty()}. If the platform does
+ * not provide the property queried, this value will be
+ * Long.MIN_VALUE.
+ *
+ * @return The queried property value, or Long.MIN_VALUE if not supported.
+ */
+ public long getLong() {
+ return mValueLong;
+ }
/*
* Parcel read/write code must be kept in sync with
* frameworks/native/services/batteryservice/BatteryProperty.cpp
@@ -92,11 +102,11 @@ public class BatteryProperty implements Parcelable {
}
public void readFromParcel(Parcel p) {
- mValueInt = p.readInt();
+ mValueLong = p.readLong();
}
public void writeToParcel(Parcel p, int flags) {
- p.writeInt(mValueInt);
+ p.writeLong(mValueLong);
}
public static final Parcelable.Creator<BatteryProperty> CREATOR
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 4857533..cf0caed 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -31,7 +31,6 @@ import android.telephony.SignalStrength;
import android.text.format.DateFormat;
import android.util.Printer;
import android.util.SparseArray;
-import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
import com.android.internal.os.BatterySipper;
@@ -601,6 +600,7 @@ public abstract class BatteryStats implements Parcelable {
public int states;
public static final int STATE2_VIDEO_ON_FLAG = 1<<0;
+ public static final int STATE2_LOW_POWER_FLAG = 1<<1;
public int states2;
// The wake lock that was acquired at this point.
@@ -622,8 +622,11 @@ public abstract class BatteryStats implements Parcelable {
public static final int EVENT_TOP = 0x0003;
// Event is about an application package that is at the top of the screen.
public static final int EVENT_SYNC = 0x0004;
+ // Events for all additional wake locks aquired/release within a wake block.
+ // These are not generated by default.
+ public static final int EVENT_WAKE_LOCK = 0x0005;
// Number of event types.
- public static final int EVENT_COUNT = 0x0005;
+ public static final int EVENT_COUNT = 0x0006;
// Mask to extract out only the type part of the event.
public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
@@ -635,6 +638,8 @@ public abstract class BatteryStats implements Parcelable {
public static final int EVENT_TOP_FINISH = EVENT_TOP | EVENT_FLAG_FINISH;
public static final int EVENT_SYNC_START = EVENT_SYNC | EVENT_FLAG_START;
public static final int EVENT_SYNC_FINISH = EVENT_SYNC | EVENT_FLAG_FINISH;
+ public static final int EVENT_WAKE_LOCK_START = EVENT_WAKE_LOCK | EVENT_FLAG_START;
+ public static final int EVENT_WAKE_LOCK_FINISH = EVENT_WAKE_LOCK | EVENT_FLAG_FINISH;
// For CMD_EVENT.
public int eventCode;
@@ -887,6 +892,11 @@ public abstract class BatteryStats implements Parcelable {
return true;
}
+ public void removeEvents(int code) {
+ int idx = code&HistoryItem.EVENT_TYPE_MASK;
+ mActiveEvents[idx] = null;
+ }
+
public HashMap<String, SparseIntArray> getStateForEvent(int code) {
return mActiveEvents[code];
}
@@ -997,6 +1007,21 @@ public abstract class BatteryStats implements Parcelable {
long elapsedRealtimeUs, int which);
/**
+ * Returns the time in microseconds that low power mode has been enabled while the device was
+ * running on battery.
+ *
+ * {@hide}
+ */
+ public abstract long getLowPowerModeEnabledTime(long elapsedRealtimeUs, int which);
+
+ /**
+ * Returns the number of times that low power mode was enabled.
+ *
+ * {@hide}
+ */
+ public abstract int getLowPowerModeEnabledCount(int which);
+
+ /**
* Returns the time in microseconds that the phone has been on while the device was
* running on battery.
*
@@ -1157,14 +1182,15 @@ public abstract class BatteryStats implements Parcelable {
public static final BitDescription[] HISTORY_STATE2_DESCRIPTIONS
= new BitDescription[] {
new BitDescription(HistoryItem.STATE2_VIDEO_ON_FLAG, "video", "v"),
+ new BitDescription(HistoryItem.STATE2_LOW_POWER_FLAG, "low_power", "lp"),
};
public static final String[] HISTORY_EVENT_NAMES = new String[] {
- "null", "proc", "fg", "top", "sync"
+ "null", "proc", "fg", "top", "sync", "wake_lock_in"
};
public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
- "Enl", "Epr", "Efg", "Etp", "Esy"
+ "Enl", "Epr", "Efg", "Etp", "Esy", "Ewl"
};
/**
@@ -1630,11 +1656,12 @@ public abstract class BatteryStats implements Parcelable {
final long totalUptime = computeUptime(rawUptime, which);
final long screenOnTime = getScreenOnTime(rawRealtime, which);
final long interactiveTime = getInteractiveTime(rawRealtime, which);
+ final long lowPowerModeEnabledTime = getLowPowerModeEnabledTime(rawRealtime, which);
final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
final long wifiOnTime = getWifiOnTime(rawRealtime, which);
final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
final long bluetoothOnTime = getBluetoothOnTime(rawRealtime, which);
-
+
StringBuilder sb = new StringBuilder(128);
SparseArray<? extends Uid> uidStats = getUidStats();
@@ -1699,7 +1726,8 @@ public abstract class BatteryStats implements Parcelable {
mobileRxTotalBytes, mobileTxTotalBytes, wifiRxTotalBytes, wifiTxTotalBytes,
fullWakeLockTimeTotal, partialWakeLockTimeTotal,
0 /*legacy input event count*/, getMobileRadioActiveTime(rawRealtime, which),
- getMobileRadioActiveAdjustedTime(which), interactiveTime / 1000);
+ getMobileRadioActiveAdjustedTime(which), interactiveTime / 1000,
+ lowPowerModeEnabledTime / 1000);
// Dump screen brightness stats
Object[] args = new Object[NUM_SCREEN_BRIGHTNESS_BINS];
@@ -2092,32 +2120,20 @@ public abstract class BatteryStats implements Parcelable {
final long screenOnTime = getScreenOnTime(rawRealtime, which);
final long interactiveTime = getInteractiveTime(rawRealtime, which);
+ final long lowPowerModeEnabledTime = getLowPowerModeEnabledTime(rawRealtime, which);
final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
final long wifiOnTime = getWifiOnTime(rawRealtime, which);
final long bluetoothOnTime = getBluetoothOnTime(rawRealtime, which);
sb.setLength(0);
sb.append(prefix);
- sb.append(" Interactive: "); formatTimeMs(sb, interactiveTime / 1000);
- sb.append("("); sb.append(formatRatioLocked(interactiveTime, whichBatteryRealtime));
- sb.append(")");
- pw.println(sb.toString());
- sb.setLength(0);
- sb.append(prefix);
sb.append(" Screen on: "); formatTimeMs(sb, screenOnTime / 1000);
sb.append("("); sb.append(formatRatioLocked(screenOnTime, whichBatteryRealtime));
sb.append(") "); sb.append(getScreenOnCount(which));
- sb.append("x, Active phone call: "); formatTimeMs(sb, phoneOnTime / 1000);
- sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime));
+ sb.append("x, Interactive: "); formatTimeMs(sb, interactiveTime / 1000);
+ sb.append("("); sb.append(formatRatioLocked(interactiveTime, whichBatteryRealtime));
sb.append(")");
pw.println(sb.toString());
- if (phoneOnTime != 0) {
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" Active phone call: "); formatTimeMs(sb, phoneOnTime / 1000);
- sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime));
- sb.append(") "); sb.append(getPhoneOnCount(which));
- }
sb.setLength(0);
sb.append(prefix);
sb.append(" Screen brightnesses:");
@@ -2139,7 +2155,24 @@ public abstract class BatteryStats implements Parcelable {
}
if (!didOne) sb.append(" (no activity)");
pw.println(sb.toString());
-
+ if (lowPowerModeEnabledTime != 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Low power mode enabled: ");
+ formatTimeMs(sb, lowPowerModeEnabledTime / 1000);
+ sb.append("(");
+ sb.append(formatRatioLocked(lowPowerModeEnabledTime, whichBatteryRealtime));
+ sb.append(")");
+ pw.println(sb.toString());
+ }
+ if (phoneOnTime != 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Active phone call: "); formatTimeMs(sb, phoneOnTime / 1000);
+ sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime));
+ sb.append(") "); sb.append(getPhoneOnCount(which));
+ }
+
// Calculate wakelock times across all uids.
long fullWakeLockTimeTotalMicros = 0;
long partialWakeLockTimeTotalMicros = 0;
@@ -3004,6 +3037,8 @@ public abstract class BatteryStats implements Parcelable {
pw.print(rec.numReadInts);
pw.print(") ");
} else {
+ pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+ pw.print(HISTORY_DATA); pw.print(',');
if (lastTime < 0) {
pw.print(rec.time - baseTime);
} else {
@@ -3190,6 +3225,7 @@ public abstract class BatteryStats implements Parcelable {
}
pw.println();
oldState = rec.states;
+ oldState2 = rec.states2;
}
}
}
@@ -3266,21 +3302,25 @@ public abstract class BatteryStats implements Parcelable {
if (rec.cmd == HistoryItem.CMD_CURRENT_TIME
|| rec.cmd == HistoryItem.CMD_RESET) {
printed = true;
+ hprinter.printNextItem(pw, rec, baseTime, checkin,
+ (flags&DUMP_VERBOSE) != 0);
+ rec.cmd = HistoryItem.CMD_UPDATE;
} else if (rec.currentTime != 0) {
printed = true;
byte cmd = rec.cmd;
rec.cmd = HistoryItem.CMD_CURRENT_TIME;
- if (checkin) {
- pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
- pw.print(HISTORY_DATA); pw.print(',');
- }
hprinter.printNextItem(pw, rec, baseTime, checkin,
(flags&DUMP_VERBOSE) != 0);
rec.cmd = cmd;
}
if (tracker != null) {
- int oldCode = rec.eventCode;
- HistoryTag oldTag = rec.eventTag;
+ if (rec.cmd != HistoryItem.CMD_UPDATE) {
+ hprinter.printNextItem(pw, rec, baseTime, checkin,
+ (flags&DUMP_VERBOSE) != 0);
+ rec.cmd = HistoryItem.CMD_UPDATE;
+ }
+ int oldEventCode = rec.eventCode;
+ HistoryTag oldEventTag = rec.eventTag;
rec.eventTag = new HistoryTag();
for (int i=0; i<HistoryItem.EVENT_COUNT; i++) {
HashMap<String, SparseIntArray> active
@@ -3296,24 +3336,18 @@ public abstract class BatteryStats implements Parcelable {
rec.eventTag.string = ent.getKey();
rec.eventTag.uid = uids.keyAt(j);
rec.eventTag.poolIdx = uids.valueAt(j);
- if (checkin) {
- pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
- pw.print(HISTORY_DATA); pw.print(',');
- }
hprinter.printNextItem(pw, rec, baseTime, checkin,
(flags&DUMP_VERBOSE) != 0);
+ rec.wakeReasonTag = null;
+ rec.wakelockTag = null;
}
}
}
- rec.eventCode = oldCode;
- rec.eventTag = oldTag;
+ rec.eventCode = oldEventCode;
+ rec.eventTag = oldEventTag;
tracker = null;
}
}
- if (checkin) {
- pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
- pw.print(HISTORY_DATA); pw.print(',');
- }
hprinter.printNextItem(pw, rec, baseTime, checkin,
(flags&DUMP_VERBOSE) != 0);
} else if (rec.eventCode != HistoryItem.EVENT_NONE) {
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index cb3d528..69b828f 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -55,6 +55,14 @@ public abstract class PowerManagerInternal {
*/
public abstract void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis);
+ public abstract boolean getLowPowerModeEnabled();
+
+ public interface LowPowerModeListener {
+ public void onLowPowerModeChanged(boolean enabled);
+ }
+
+ public abstract void registerLowPowerModeObserver(LowPowerModeListener listener);
+
// TODO: Remove this and retrieve as a local service instead.
public abstract void setPolicy(WindowManagerPolicy policy);
}
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index 29f2545..39cb826 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -66,7 +66,7 @@ public class VolumePreference extends SeekBarDialogPreference implements
}
public VolumePreference(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
+ this(context, attrs, com.android.internal.R.attr.dialogPreferenceStyle);
}
public void setStreamType(int streamType) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 89f4388..d09bb88 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -769,6 +769,17 @@ public final class Settings {
public static final String
ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
+ /**
+ * Activity Action: Show Device Name Settings.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you safeguard
+ * against ithis.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String DEVICE_NAME_SETTINGS = "android.settings.DEVICE_NAME";
+
// End of Intent actions for Settings
/**
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 5a432dc..9a70099 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -24,7 +24,6 @@ import android.util.ArrayMap;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.SparseArray;
-import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.view.SurfaceView;
import android.view.TextureView;
@@ -108,6 +107,40 @@ public abstract class Transition implements Cloneable {
private static final String LOG_TAG = "Transition";
static final boolean DBG = false;
+ /**
+ * With {@link #setMatchOrder(int...)}, chooses to match by View instance.
+ */
+ public static final int MATCH_INSTANCE = 0x1;
+ private static final int MATCH_FIRST = MATCH_INSTANCE;
+
+ /**
+ * With {@link #setMatchOrder(int...)}, chooses to match by
+ * {@link android.view.View#getViewName()}. Null names will not be matched.
+ */
+ public static final int MATCH_VIEW_NAME = 0x2;
+
+ /**
+ * With {@link #setMatchOrder(int...)}, chooses to match by
+ * {@link android.view.View#getId()}. Negative IDs will not be matched.
+ */
+ public static final int MATCH_ID = 0x3;
+
+ /**
+ * With {@link #setMatchOrder(int...)}, chooses to match by the {@link android.widget.Adapter}
+ * item id. When {@link android.widget.Adapter#hasStableIds()} returns false, no match
+ * will be made for items.
+ */
+ public static final int MATCH_ITEM_ID = 0x4;
+
+ private static final int MATCH_LAST = MATCH_ITEM_ID;
+
+ private static final int[] DEFAULT_MATCH_ORDER = {
+ MATCH_VIEW_NAME,
+ MATCH_INSTANCE,
+ MATCH_ID,
+ MATCH_ITEM_ID,
+ };
+
private String mName = getClass().getName();
long mStartDelay = -1;
@@ -127,6 +160,7 @@ public abstract class Transition implements Cloneable {
private TransitionValuesMaps mStartValues = new TransitionValuesMaps();
private TransitionValuesMaps mEndValues = new TransitionValuesMaps();
TransitionSet mParent = null;
+ private int[] mMatchOrder = DEFAULT_MATCH_ORDER;
// Per-animator information used for later canceling when future transitions overlap
private static ThreadLocal<ArrayMap<Animator, AnimationInfo>> sRunningAnimators =
@@ -338,6 +372,53 @@ public abstract class Transition implements Cloneable {
}
/**
+ * Sets the order in which Transition matches View start and end values.
+ * <p>
+ * The default behavior is to match first by {@link android.view.View#getViewName()},
+ * then by View instance, then by {@link android.view.View#getId()} and finally
+ * by its item ID if it is in a direct child of ListView. The caller can
+ * choose to have only some or all of the values of {@link #MATCH_INSTANCE},
+ * {@link #MATCH_VIEW_NAME}, {@link #MATCH_ITEM_ID}, and {@link #MATCH_ID}. Only
+ * the match algorithms supplied will be used to determine whether Views are the
+ * the same in both the start and end Scene. Views that do not match will be considered
+ * as entering or leaving the Scene.
+ * </p>
+ * @param matches A list of zero or more of {@link #MATCH_INSTANCE},
+ * {@link #MATCH_VIEW_NAME}, {@link #MATCH_ITEM_ID}, and {@link #MATCH_ID}.
+ * If none are provided, then the default match order will be set.
+ */
+ public void setMatchOrder(int... matches) {
+ if (matches == null || matches.length == 0) {
+ mMatchOrder = DEFAULT_MATCH_ORDER;
+ } else {
+ for (int i = 0; i < matches.length; i++) {
+ int match = matches[i];
+ if (!isValidMatch(match)) {
+ throw new IllegalArgumentException("matches contains invalid value");
+ }
+ if (alreadyContains(matches, i)) {
+ throw new IllegalArgumentException("matches contains a duplicate value");
+ }
+ }
+ mMatchOrder = matches.clone();
+ }
+ }
+
+ private static boolean isValidMatch(int match) {
+ return (match >= MATCH_FIRST && match <= MATCH_LAST);
+ }
+
+ private static boolean alreadyContains(int[] array, int searchIndex) {
+ int value = array[searchIndex];
+ for (int i = 0; i < searchIndex; i++) {
+ if (array[i] == value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Match start/end values by View instance. Adds matched values to startValuesList
* and endValuesList and removes them from unmatchedStart and unmatchedEnd.
*/
@@ -464,6 +545,37 @@ public abstract class Transition implements Cloneable {
}
}
+ private void matchStartAndEnd(TransitionValuesMaps startValues,
+ TransitionValuesMaps endValues,
+ ArrayList<TransitionValues> startValuesList,
+ ArrayList<TransitionValues> endValuesList) {
+ ArrayMap<View, TransitionValues> unmatchedStart =
+ new ArrayMap<View, TransitionValues>(startValues.viewValues);
+ ArrayMap<View, TransitionValues> unmatchedEnd =
+ new ArrayMap<View, TransitionValues>(endValues.viewValues);
+
+ for (int i = 0; i < mMatchOrder.length; i++) {
+ switch (mMatchOrder[i]) {
+ case MATCH_INSTANCE:
+ matchInstances(startValuesList, endValuesList, unmatchedStart, unmatchedEnd);
+ break;
+ case MATCH_VIEW_NAME:
+ matchNames(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
+ startValues.nameValues, endValues.nameValues);
+ break;
+ case MATCH_ID:
+ matchIds(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
+ startValues.idValues, endValues.idValues);
+ break;
+ case MATCH_ITEM_ID:
+ matchItemIds(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
+ startValues.itemIdValues, endValues.itemIdValues);
+ break;
+ }
+ }
+ addUnmatched(startValuesList, endValuesList, unmatchedStart, unmatchedEnd);
+ }
+
/**
* This method, essentially a wrapper around all calls to createAnimator for all
* possible target views, is called with the entire set of start/end
@@ -480,21 +592,9 @@ public abstract class Transition implements Cloneable {
if (DBG) {
Log.d(LOG_TAG, "createAnimators() for " + this);
}
- ArrayMap<View, TransitionValues> unmatchedStart =
- new ArrayMap<View, TransitionValues>(startValues.viewValues);
- ArrayMap<View, TransitionValues> unmatchedEnd =
- new ArrayMap<View, TransitionValues>(endValues.viewValues);
-
ArrayList<TransitionValues> startValuesList = new ArrayList<TransitionValues>();
ArrayList<TransitionValues> endValuesList = new ArrayList<TransitionValues>();
- matchNames(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
- startValues.nameValues, endValues.nameValues);
- matchInstances(startValuesList, endValuesList, unmatchedStart, unmatchedEnd);
- matchIds(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
- startValues.idValues, endValues.idValues);
- matchItemIds(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
- startValues.itemIdValues, endValues.itemIdValues);
- addUnmatched(startValuesList, endValuesList, unmatchedStart, unmatchedEnd);
+ matchStartAndEnd(startValues, endValues, startValuesList, endValuesList);
ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
long minStartDelay = Long.MAX_VALUE;
diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java
index 04f8672..f4b562f 100644
--- a/core/java/android/transition/TransitionInflater.java
+++ b/core/java/android/transition/TransitionInflater.java
@@ -30,6 +30,7 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.StringTokenizer;
/**
* This class inflates scenes and transitions from resource files.
@@ -40,6 +41,10 @@ import java.util.ArrayList;
* and {@link android.R.styleable#TransitionManager}.
*/
public class TransitionInflater {
+ private static final String MATCH_INSTANCE = "instance";
+ private static final String MATCH_VIEW_NAME = "viewName";
+ private static final String MATCH_ID = "id";
+ private static final String MATCH_ITEM_ID = "itemId";
private Context mContext;
@@ -266,6 +271,33 @@ public class TransitionInflater {
}
}
+ private int[] parseMatchOrder(String matchOrderString) {
+ StringTokenizer st = new StringTokenizer(matchOrderString, ",");
+ int matches[] = new int[st.countTokens()];
+ int index = 0;
+ while (st.hasMoreTokens()) {
+ String token = st.nextToken().trim();
+ if (MATCH_ID.equalsIgnoreCase(token)) {
+ matches[index] = Transition.MATCH_ID;
+ } else if (MATCH_INSTANCE.equalsIgnoreCase(token)) {
+ matches[index] = Transition.MATCH_INSTANCE;
+ } else if (MATCH_VIEW_NAME.equalsIgnoreCase(token)) {
+ matches[index] = Transition.MATCH_VIEW_NAME;
+ } else if (MATCH_ITEM_ID.equalsIgnoreCase(token)) {
+ matches[index] = Transition.MATCH_ITEM_ID;
+ } else if (token.isEmpty()) {
+ int[] smallerMatches = new int[matches.length - 1];
+ System.arraycopy(matches, 0, smallerMatches, 0, index);
+ matches = smallerMatches;
+ index--;
+ } else {
+ throw new RuntimeException("Unknown match type in matchOrder: '" + token + "'");
+ }
+ index++;
+ }
+ return matches;
+ }
+
private Transition loadTransition(Transition transition, AttributeSet attrs)
throws Resources.NotFoundException {
@@ -284,6 +316,11 @@ public class TransitionInflater {
if (resID > 0) {
transition.setInterpolator(AnimationUtils.loadInterpolator(mContext, resID));
}
+ String matchOrder =
+ a.getString(com.android.internal.R.styleable.Transition_matchOrder);
+ if (matchOrder != null) {
+ transition.setMatchOrder(parseMatchOrder(matchOrder));
+ }
a.recycle();
return transition;
}
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 0cfde94..b2839cb 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -387,6 +387,10 @@ public class RenderNode {
nSetClipToOutline(mNativeRenderNode, clipToOutline);
}
+ public boolean getClipToOutline() {
+ return nGetClipToOutline(mNativeRenderNode);
+ }
+
/**
* Controls the RenderNode's circular reveal clip.
*/
@@ -919,6 +923,7 @@ public class RenderNode {
private static native void nSetAnimationMatrix(long renderNode, long animationMatrix);
private static native boolean nHasOverlappingRendering(long renderNode);
+ private static native boolean nGetClipToOutline(long renderNode);
private static native float nGetAlpha(long renderNode);
private static native float nGetLeft(long renderNode);
private static native float nGetTop(long renderNode);
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index ec4d560..f14e73f 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -21,7 +21,6 @@ import android.graphics.Canvas;
import android.graphics.CanvasProperty;
import android.graphics.Paint;
import android.util.SparseIntArray;
-import android.util.TimeUtils;
import com.android.internal.util.VirtualRefBasePtr;
import com.android.internal.view.animation.FallbackLUTInterpolator;
@@ -72,10 +71,6 @@ public final class RenderNodeAnimator {
put(ViewPropertyAnimator.ALPHA, ALPHA);
}};
- // Keep in sync DeltaValueType in Animator.h
- public static final int DELTA_TYPE_ABSOLUTE = 0;
- public static final int DELTA_TYPE_DELTA = 1;
-
private VirtualRefBasePtr mNativePtr;
private RenderNode mTarget;
@@ -86,22 +81,21 @@ public final class RenderNodeAnimator {
return sViewPropertyAnimatorMap.get(viewProperty);
}
- public RenderNodeAnimator(int property, int deltaType, float deltaValue) {
+ public RenderNodeAnimator(int property, float finalValue) {
init(nCreateAnimator(new WeakReference<RenderNodeAnimator>(this),
- property, deltaType, deltaValue));
+ property, finalValue));
}
- public RenderNodeAnimator(CanvasProperty<Float> property, int deltaType, float deltaValue) {
+ public RenderNodeAnimator(CanvasProperty<Float> property, float finalValue) {
init(nCreateCanvasPropertyFloatAnimator(
new WeakReference<RenderNodeAnimator>(this),
- property.getNativeContainer(), deltaType, deltaValue));
+ property.getNativeContainer(), finalValue));
}
- public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField,
- int deltaType, float deltaValue) {
+ public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField, float finalValue) {
init(nCreateCanvasPropertyPaintAnimator(
new WeakReference<RenderNodeAnimator>(this),
- property.getNativeContainer(), paintField, deltaType, deltaValue));
+ property.getNativeContainer(), paintField, finalValue));
}
private void init(long ptr) {
@@ -182,11 +176,11 @@ public final class RenderNodeAnimator {
}
private static native long nCreateAnimator(WeakReference<RenderNodeAnimator> weakThis,
- int property, int deltaValueType, float deltaValue);
+ int property, float deltaValue);
private static native long nCreateCanvasPropertyFloatAnimator(WeakReference<RenderNodeAnimator> weakThis,
- long canvasProperty, int deltaValueType, float deltaValue);
+ long canvasProperty, float deltaValue);
private static native long nCreateCanvasPropertyPaintAnimator(WeakReference<RenderNodeAnimator> weakThis,
- long canvasProperty, int paintField, int deltaValueType, float deltaValue);
+ long canvasProperty, int paintField, float deltaValue);
private static native void nSetDuration(long nativePtr, int duration);
private static native int nGetDuration(long nativePtr);
private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e829141..5141877 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2774,8 +2774,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* @hide
+ *
+ * Makes system ui transparent.
+ */
+ public static final int SYSTEM_UI_TRANSPARENT = 0x00008000;
+
+ /**
+ * @hide
*/
- public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x0000FFFF;
+ public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00007FFF;
/**
* These are the system UI flags that can be cleared by events outside
@@ -7147,6 +7154,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (viewRootImpl != null) {
viewRootImpl.setAccessibilityFocus(this, null);
}
+ Rect rect = (mAttachInfo != null) ? mAttachInfo.mTmpInvalRect : new Rect();
+ getDrawingRect(rect);
+ requestRectangleOnScreen(rect, false);
invalidate();
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
return true;
@@ -10696,9 +10706,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mRenderNode.setOutline(mOutline);
}
- // TODO: remove
- public final boolean getClipToOutline() { return false; }
- public void setClipToOutline(boolean clipToOutline) {}
+ public final boolean getClipToOutline() {
+ return mRenderNode.getClipToOutline();
+ }
+
+ public void setClipToOutline(boolean clipToOutline) {
+ // TODO: add a fast invalidation here
+ if (getClipToOutline() != clipToOutline) {
+ mRenderNode.setClipToOutline(clipToOutline);
+ }
+ }
private void queryOutlineFromBackgroundIfUndefined() {
if ((mPrivateFlags3 & PFLAG3_OUTLINE_DEFINED) == 0) {
@@ -10707,7 +10724,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mOutline = new Outline();
} else {
//invalidate outline, to ensure background calculates it
- mOutline.set(null);
+ mOutline.reset();
}
if (mBackground.getOutline(mOutline)) {
if (!mOutline.isValid()) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 92a42b7..b821a3e 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2318,8 +2318,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* in Activity transitions. If false, the ViewGroup won't transition,
* only its children. If true, the entire ViewGroup will transition
* together.
- * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
- * android.app.ActivityOptions.ActivityTransitionListener)
+ * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.app.Activity,
+ * android.util.Pair[])
*/
public void setTransitionGroup(boolean isTransitionGroup) {
mGroupFlags |= FLAG_IS_TRANSITION_GROUP_SET;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 375f5e3..ecc4586 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -642,9 +642,7 @@ public abstract class Window {
final WindowManager.LayoutParams attrs = getAttributes();
attrs.width = width;
attrs.height = height;
- if (mCallback != null) {
- mCallback.onWindowAttributesChanged(attrs);
- }
+ dispatchWindowAttributesChanged(attrs);
}
/**
@@ -661,9 +659,7 @@ public abstract class Window {
{
final WindowManager.LayoutParams attrs = getAttributes();
attrs.gravity = gravity;
- if (mCallback != null) {
- mCallback.onWindowAttributesChanged(attrs);
- }
+ dispatchWindowAttributesChanged(attrs);
}
/**
@@ -675,9 +671,7 @@ public abstract class Window {
public void setType(int type) {
final WindowManager.LayoutParams attrs = getAttributes();
attrs.type = type;
- if (mCallback != null) {
- mCallback.onWindowAttributesChanged(attrs);
- }
+ dispatchWindowAttributesChanged(attrs);
}
/**
@@ -700,9 +694,7 @@ public abstract class Window {
attrs.format = mDefaultWindowFormat;
mHaveWindowFormat = false;
}
- if (mCallback != null) {
- mCallback.onWindowAttributesChanged(attrs);
- }
+ dispatchWindowAttributesChanged(attrs);
}
/**
@@ -715,9 +707,7 @@ public abstract class Window {
public void setWindowAnimations(int resId) {
final WindowManager.LayoutParams attrs = getAttributes();
attrs.windowAnimations = resId;
- if (mCallback != null) {
- mCallback.onWindowAttributesChanged(attrs);
- }
+ dispatchWindowAttributesChanged(attrs);
}
/**
@@ -735,9 +725,7 @@ public abstract class Window {
} else {
mHasSoftInputMode = false;
}
- if (mCallback != null) {
- mCallback.onWindowAttributesChanged(attrs);
- }
+ dispatchWindowAttributesChanged(attrs);
}
/**
@@ -793,14 +781,19 @@ public abstract class Window {
attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY;
}
mForcedWindowFlags |= mask;
- if (mCallback != null) {
- mCallback.onWindowAttributesChanged(attrs);
- }
+ dispatchWindowAttributesChanged(attrs);
}
private void setPrivateFlags(int flags, int mask) {
final WindowManager.LayoutParams attrs = getAttributes();
attrs.privateFlags = (attrs.privateFlags & ~mask) | (flags & mask);
+ dispatchWindowAttributesChanged(attrs);
+ }
+
+ /**
+ * {@hide}
+ */
+ protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) {
if (mCallback != null) {
mCallback.onWindowAttributesChanged(attrs);
}
@@ -818,9 +811,7 @@ public abstract class Window {
final WindowManager.LayoutParams attrs = getAttributes();
attrs.dimAmount = amount;
mHaveDimAmount = true;
- if (mCallback != null) {
- mCallback.onWindowAttributesChanged(attrs);
- }
+ dispatchWindowAttributesChanged(attrs);
}
/**
@@ -835,9 +826,7 @@ public abstract class Window {
*/
public void setAttributes(WindowManager.LayoutParams a) {
mWindowAttributes.copyFrom(a);
- if (mCallback != null) {
- mCallback.onWindowAttributesChanged(mWindowAttributes);
- }
+ dispatchWindowAttributesChanged(mWindowAttributes);
}
/**
@@ -1269,9 +1258,7 @@ public abstract class Window {
if (!mHaveWindowFormat) {
final WindowManager.LayoutParams attrs = getAttributes();
attrs.format = format;
- if (mCallback != null) {
- mCallback.onWindowAttributesChanged(attrs);
- }
+ dispatchWindowAttributesChanged(attrs);
}
}
@@ -1527,4 +1514,44 @@ public abstract class Window {
* until the called Activity's exiting transition completes.
*/
public boolean getAllowExitTransitionOverlap() { return true; }
+
+ /**
+ * @return the color of the status bar.
+ */
+ public abstract int getStatusBarColor();
+
+ /**
+ * Sets the color of the status bar to {@param color}.
+ *
+ * For this to take effect,
+ * the window must be drawing the system bar backgrounds with
+ * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} and
+ * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS} must not be set.
+ *
+ * If {@param color} is not opaque, consider setting
+ * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
+ * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
+ */
+ public abstract void setStatusBarColor(int color);
+
+ /**
+ * @return the color of the navigation bar.
+ */
+ public abstract int getNavigationBarColor();
+
+ /**
+ * Sets the color of the navigation bar to {@param color}.
+ *
+ * For this to take effect,
+ * the window must be drawing the system bar backgrounds with
+ * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} and
+ * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION} must not be set.
+ *
+ * If {@param color} is not opaque, consider setting
+ * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
+ * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
+ */
+ public abstract void setNavigationBarColor(int color);
+
+
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 032a82f..031ad80 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -915,6 +915,14 @@ public interface WindowManager extends ViewManager {
public static final int FLAG_NEEDS_MENU_KEY = 0x40000000;
/**
+ * Flag indicating that this Window is responsible for drawing the background for the
+ * system bars. If set, the system bars are drawn with a transparent background and the
+ * corresponding areas in this window are filled with the colors specified in
+ * {@link Window#getStatusBarColor()} and {@link Window#getNavigationBarColor()}.
+ */
+ public static final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000;
+
+ /**
* Various behavioral options/flags. Default is none.
*
* @see #FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
@@ -941,6 +949,7 @@ public interface WindowManager extends ViewManager {
* @see #FLAG_SPLIT_TOUCH
* @see #FLAG_HARDWARE_ACCELERATED
* @see #FLAG_LOCAL_FOCUS_MODE
+ * @see #FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
*/
@ViewDebug.ExportedProperty(flagMapping = {
@ViewDebug.FlagToString(mask = FLAG_ALLOW_LOCK_WHILE_SCREEN_ON, equals = FLAG_ALLOW_LOCK_WHILE_SCREEN_ON,
@@ -998,7 +1007,9 @@ public interface WindowManager extends ViewManager {
@ViewDebug.FlagToString(mask = FLAG_TRANSLUCENT_STATUS, equals = FLAG_TRANSLUCENT_STATUS,
name = "FLAG_TRANSLUCENT_STATUS"),
@ViewDebug.FlagToString(mask = FLAG_TRANSLUCENT_NAVIGATION, equals = FLAG_TRANSLUCENT_NAVIGATION,
- name = "FLAG_TRANSLUCENT_NAVIGATION")
+ name = "FLAG_TRANSLUCENT_NAVIGATION"),
+ @ViewDebug.FlagToString(mask = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, equals = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+ name = "FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS")
})
public int flags;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 9d10930..34967df 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -17,15 +17,19 @@
package android.view.accessibility;
import android.accessibilityservice.AccessibilityServiceInfo;
+import android.annotation.Nullable;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.InputType;
+import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.LongArray;
import android.util.Pools.SynchronizedPool;
import android.view.View;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -112,7 +116,7 @@ public class AccessibilityNodeInfo implements Parcelable {
public static final int ACTION_SELECT = 0x00000004;
/**
- * Action that unselects the node.
+ * Action that deselects the node.
*/
public static final int ACTION_CLEAR_SELECTION = 0x00000008;
@@ -307,6 +311,18 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public static final int ACTION_SET_TEXT = 0x00200000;
+ private static final int LAST_LEGACY_STANDARD_ACTION = ACTION_SET_TEXT;
+
+ /**
+ * Mask to see if the value is larger than the largest ACTION_ constant
+ */
+ private static final int ACTION_TYPE_MASK = 0xFF000000;
+
+ /**
+ * Mask to define standard not legacy actions.
+ */
+ private static final int STANDARD_NON_LEGACY_ACTION_MASK = 0x01000000;
+
// Action arguments
/**
@@ -548,7 +564,7 @@ public class AccessibilityNodeInfo implements Parcelable {
private String mViewIdResourceName;
private LongArray mChildNodeIds;
- private int mActions;
+ private ArrayList<AccessibilityAction> mActions;
private int mMovementGranularities;
@@ -875,6 +891,17 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Gets the actions that can be performed on the node.
+ */
+ public List<AccessibilityAction> getActionList() {
+ if (mActions == null) {
+ return Collections.emptyList();
+ }
+
+ return mActions;
+ }
+
+ /**
+ * Gets the actions that can be performed on the node.
*
* @return The bit mask of with actions.
*
@@ -892,9 +919,61 @@ public class AccessibilityNodeInfo implements Parcelable {
* @see AccessibilityNodeInfo#ACTION_PREVIOUS_HTML_ELEMENT
* @see AccessibilityNodeInfo#ACTION_SCROLL_FORWARD
* @see AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD
+ *
+ * @deprecated Use {@link #getActionList()}.
*/
+ @Deprecated
public int getActions() {
- return mActions;
+ int returnValue = 0;
+
+ if (mActions == null) {
+ return returnValue;
+ }
+
+ final int actionSize = mActions.size();
+ for (int i = 0; i < actionSize; i++) {
+ int actionId = mActions.get(i).getId();
+ if (actionId <= LAST_LEGACY_STANDARD_ACTION) {
+ returnValue |= actionId;
+ }
+ }
+
+ return returnValue;
+ }
+
+ /**
+ * Adds an action that can be performed on the node.
+ * <p>
+ * To add a standard action use the static constants on {@link AccessibilityAction}.
+ * To add a custom action create a new {@link AccessibilityAction} by passing in a
+ * resource id from your application as the action id and an optional label that
+ * describes the action. To override one of the standard actions use as the action
+ * id of a standard action id such as {@link #ACTION_CLICK} and an optional label that
+ * describes the action.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param action The action.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void addAction(AccessibilityAction action) {
+ enforceNotSealed();
+
+ if (action == null) {
+ return;
+ }
+
+ if (mActions == null) {
+ mActions = new ArrayList<AccessibilityAction>();
+ }
+
+ mActions.remove(action);
+ mActions.add(action);
}
/**
@@ -908,10 +987,21 @@ public class AccessibilityNodeInfo implements Parcelable {
* @param action The action.
*
* @throws IllegalStateException If called from an AccessibilityService.
+ * @throws IllegalArgumentException If the argument is not one of the standard actions.
+ *
+ * @deprecated This has been deprecated for {@link #addAction(AccessibilityAction)}
*/
+ @Deprecated
public void addAction(int action) {
enforceNotSealed();
- mActions |= action;
+
+ AccessibilityAction newAction = getActionSingleton(action);
+ if (newAction == null) {
+ // This means it is not one of the standard actions
+ throw new IllegalArgumentException("Argument is not one of the standard actions");
+ }
+
+ addAction(newAction);
}
/**
@@ -923,13 +1013,40 @@ public class AccessibilityNodeInfo implements Parcelable {
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
*
- * @param action The action.
+ * @param action The action to be removed.
*
* @throws IllegalStateException If called from an AccessibilityService.
+ * @deprecated Use {@link #removeAction(AccessibilityAction)}
*/
+ @Deprecated
public void removeAction(int action) {
enforceNotSealed();
- mActions &= ~action;
+
+ removeAction(getActionSingleton(action));
+ }
+
+ /**
+ * Removes an action that can be performed on the node. If the action was
+ * not already added to the node, calling this method has no effect.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param action The action to be removed.
+ * @return The action removed from the list of actions.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public boolean removeAction(AccessibilityAction action) {
+ enforceNotSealed();
+
+ if (mActions == null || action == null) {
+ return false;
+ }
+
+ return mActions.remove(action);
}
/**
@@ -2307,7 +2424,29 @@ public class AccessibilityNodeInfo implements Parcelable {
parcel.writeInt(mBoundsInScreen.left);
parcel.writeInt(mBoundsInScreen.right);
- parcel.writeInt(mActions);
+ if (mActions != null && !mActions.isEmpty()) {
+ final int actionCount = mActions.size();
+ parcel.writeInt(actionCount);
+
+ int defaultLegacyStandardActions = 0;
+ for (int i = 0; i < actionCount; i++) {
+ AccessibilityAction action = mActions.get(i);
+ if (isDefaultLegacyStandardAction(action)) {
+ defaultLegacyStandardActions |= action.getId();
+ }
+ }
+ parcel.writeInt(defaultLegacyStandardActions);
+
+ for (int i = 0; i < actionCount; i++) {
+ AccessibilityAction action = mActions.get(i);
+ if (!isDefaultLegacyStandardAction(action)) {
+ parcel.writeInt(action.getId());
+ parcel.writeCharSequence(action.getLabel());
+ }
+ }
+ } else {
+ parcel.writeInt(0);
+ }
parcel.writeInt(mMovementGranularities);
@@ -2388,7 +2527,17 @@ public class AccessibilityNodeInfo implements Parcelable {
mText = other.mText;
mContentDescription = other.mContentDescription;
mViewIdResourceName = other.mViewIdResourceName;
- mActions= other.mActions;
+
+ final ArrayList<AccessibilityAction> otherActions = other.mActions;
+ if (otherActions != null && otherActions.size() > 0) {
+ if (mActions == null) {
+ mActions = new ArrayList(otherActions);
+ } else {
+ mActions.clear();
+ mActions.addAll(other.mActions);
+ }
+ }
+
mBooleanProperties = other.mBooleanProperties;
mMovementGranularities = other.mMovementGranularities;
@@ -2452,7 +2601,17 @@ public class AccessibilityNodeInfo implements Parcelable {
mBoundsInScreen.left = parcel.readInt();
mBoundsInScreen.right = parcel.readInt();
- mActions = parcel.readInt();
+ final int actionCount = parcel.readInt();
+ if (actionCount > 0) {
+ final int legacyStandardActions = parcel.readInt();
+ addLegacyStandardActions(legacyStandardActions);
+ final int nonLegacyActionCount = actionCount - Integer.bitCount(legacyStandardActions);
+ for (int i = 0; i < nonLegacyActionCount; i++) {
+ AccessibilityAction action = new AccessibilityAction(
+ parcel.readInt(), parcel.readCharSequence());
+ addAction(action);
+ }
+ }
mMovementGranularities = parcel.readInt();
@@ -2524,7 +2683,9 @@ public class AccessibilityNodeInfo implements Parcelable {
mText = null;
mContentDescription = null;
mViewIdResourceName = null;
- mActions = 0;
+ if (mActions != null) {
+ mActions.clear();
+ }
mTextSelectionStart = UNDEFINED_SELECTION_INDEX;
mTextSelectionEnd = UNDEFINED_SELECTION_INDEX;
mInputType = InputType.TYPE_NULL;
@@ -2546,6 +2707,33 @@ public class AccessibilityNodeInfo implements Parcelable {
}
}
+ private static boolean isDefaultLegacyStandardAction(AccessibilityAction action) {
+ return (action.getId() <= LAST_LEGACY_STANDARD_ACTION
+ && TextUtils.isEmpty(action.getLabel()));
+ }
+
+ private static AccessibilityAction getActionSingleton(int actionId) {
+ final int actions = AccessibilityAction.sStandardActions.size();
+ for (int i = 0; i < actions; i++) {
+ AccessibilityAction currentAction = AccessibilityAction.sStandardActions.valueAt(i);
+ if (actionId == currentAction.getId()) {
+ return currentAction;
+ }
+ }
+
+ return null;
+ }
+
+ private void addLegacyStandardActions(int actionMask) {
+ int remainingIds = actionMask;
+ while (remainingIds > 0) {
+ final int id = 1 << Integer.numberOfTrailingZeros(remainingIds);
+ remainingIds &= ~id;
+ AccessibilityAction action = getActionSingleton(id);
+ addAction(action);
+ }
+ }
+
/**
* Gets the human readable action symbolic name.
*
@@ -2709,20 +2897,429 @@ public class AccessibilityNodeInfo implements Parcelable {
builder.append("; longClickable: ").append(isLongClickable());
builder.append("; enabled: ").append(isEnabled());
builder.append("; password: ").append(isPassword());
- builder.append("; scrollable: " + isScrollable());
-
- builder.append("; [");
- for (int actionBits = mActions; actionBits != 0;) {
- final int action = 1 << Integer.numberOfTrailingZeros(actionBits);
- actionBits &= ~action;
- builder.append(getActionSymbolicName(action));
- if (actionBits != 0) {
- builder.append(", ");
+ builder.append("; scrollable: ").append(isScrollable());
+ builder.append("; actions: ").append(mActions);
+
+ return builder.toString();
+ }
+
+ /**
+ * A class defining an action that can be performed on an {@link AccessibilityNodeInfo}.
+ * Each action has a unique id that is mandatory and optional data.
+ * <p>
+ * There are three categories of actions:
+ * <ul>
+ * <li><strong>Standard actions</strong> - These are actions that are reported and
+ * handled by the standard UI widgets in the platform. For each standard action
+ * there is a static constant defined in this class, e.g. {@link #ACTION_FOCUS}.
+ * </li>
+ * <li><strong>Custom actions action</strong> - These are actions that are reported
+ * and handled by custom widgets. i.e. ones that are not part of the UI toolkit. For
+ * example, an application may define a custom action for clearing the user history.
+ * </li>
+ * <li><strong>Overriden standard actions</strong> - These are actions that override
+ * standard actions to customize them. For example, an app may add a label to the
+ * standard click action to announce that this action clears browsing history.
+ * </ul>
+ * </p>
+ */
+ public static final class AccessibilityAction {
+
+ /**
+ * Action that gives input focus to the node.
+ */
+ public static final AccessibilityAction ACTION_FOCUS =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_FOCUS, null);
+
+ /**
+ * Action that clears input focus of the node.
+ */
+ public static final AccessibilityAction ACTION_CLEAR_FOCUS =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CLEAR_FOCUS, null);
+
+ /**
+ * Action that selects the node.
+ */
+ public static final AccessibilityAction ACTION_SELECT =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_SELECT, null);
+
+ /**
+ * Action that deselects the node.
+ */
+ public static final AccessibilityAction ACTION_CLEAR_SELECTION =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CLEAR_SELECTION, null);
+
+ /**
+ * Action that clicks on the node info.
+ */
+ public static final AccessibilityAction ACTION_CLICK =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CLICK, null);
+
+ /**
+ * Action that long clicks on the node.
+ */
+ public static final AccessibilityAction ACTION_LONG_CLICK =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_LONG_CLICK, null);
+
+ /**
+ * Action that gives accessibility focus to the node.
+ */
+ public static final AccessibilityAction ACTION_ACCESSIBILITY_FOCUS =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
+
+ /**
+ * Action that clears accessibility focus of the node.
+ */
+ public static final AccessibilityAction ACTION_CLEAR_ACCESSIBILITY_FOCUS =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
+
+ /**
+ * Action that requests to go to the next entity in this node's text
+ * at a given movement granularity. For example, move to the next character,
+ * word, etc.
+ * <p>
+ * <strong>Arguments:</strong>
+ * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT},
+ * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
+ * <strong>Example:</strong> Move to the previous character and do not extend selection.
+ * <code><pre><p>
+ * Bundle arguments = new Bundle();
+ * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+ * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
+ * false);
+ * info.performAction(AccessibilityAction.ACTION_NEXT_AT_MOVEMENT_GRANULARITY.getId(),
+ * arguments);
+ * </code></pre></p>
+ * </p>
+ *
+ * @see AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
+ * @see AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
+ *
+ * @see AccessibilityNodeInfo#setMovementGranularities(int)
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
+ * @see AccessibilityNodeInfo#getMovementGranularities()
+ * AccessibilityNodeInfo.getMovementGranularities()
+ *
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_CHARACTER
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_WORD
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_LINE
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PARAGRAPH
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PAGE
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE
+ */
+ public static final AccessibilityAction ACTION_NEXT_AT_MOVEMENT_GRANULARITY =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, null);
+
+ /**
+ * Action that requests to go to the previous entity in this node's text
+ * at a given movement granularity. For example, move to the next character,
+ * word, etc.
+ * <p>
+ * <strong>Arguments:</strong>
+ * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT},
+ * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
+ * <strong>Example:</strong> Move to the next character and do not extend selection.
+ * <code><pre><p>
+ * Bundle arguments = new Bundle();
+ * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+ * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
+ * false);
+ * info.performAction(AccessibilityAction.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY.getId(),
+ * arguments);
+ * </code></pre></p>
+ * </p>
+ *
+ * @see AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
+ * @see AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
+ *
+ * @see AccessibilityNodeInfo#setMovementGranularities(int)
+ * AccessibilityNodeInfo.setMovementGranularities(int)
+ * @see AccessibilityNodeInfo#getMovementGranularities()
+ * AccessibilityNodeInfo.getMovementGranularities()
+ *
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_CHARACTER
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_WORD
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_LINE
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PARAGRAPH
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PAGE
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE
+ */
+ public static final AccessibilityAction ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, null);
+
+ /**
+ * Action to move to the next HTML element of a given type. For example, move
+ * to the BUTTON, INPUT, TABLE, etc.
+ * <p>
+ * <strong>Arguments:</strong>
+ * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
+ * <strong>Example:</strong>
+ * <code><pre><p>
+ * Bundle arguments = new Bundle();
+ * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
+ * info.performAction(AccessibilityAction.ACTION_NEXT_HTML_ELEMENT.getId(), arguments);
+ * </code></pre></p>
+ * </p>
+ */
+ public static final AccessibilityAction ACTION_NEXT_HTML_ELEMENT =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, null);
+
+ /**
+ * Action to move to the previous HTML element of a given type. For example, move
+ * to the BUTTON, INPUT, TABLE, etc.
+ * <p>
+ * <strong>Arguments:</strong>
+ * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
+ * <strong>Example:</strong>
+ * <code><pre><p>
+ * Bundle arguments = new Bundle();
+ * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
+ * info.performAction(AccessibilityAction.ACTION_PREVIOUS_HTML_ELEMENT.getId(), arguments);
+ * </code></pre></p>
+ * </p>
+ */
+ public static final AccessibilityAction ACTION_PREVIOUS_HTML_ELEMENT =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, null);
+
+ /**
+ * Action to scroll the node content forward.
+ */
+ public static final AccessibilityAction ACTION_SCROLL_FORWARD =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, null);
+
+ /**
+ * Action to scroll the node content backward.
+ */
+ public static final AccessibilityAction ACTION_SCROLL_BACKWARD =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, null);
+
+ /**
+ * Action to copy the current selection to the clipboard.
+ */
+ public static final AccessibilityAction ACTION_COPY =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_COPY, null);
+
+ /**
+ * Action to paste the current clipboard content.
+ */
+ public static final AccessibilityAction ACTION_PASTE =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_PASTE, null);
+
+ /**
+ * Action to cut the current selection and place it to the clipboard.
+ */
+ public static final AccessibilityAction ACTION_CUT =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CUT, null);
+
+ /**
+ * Action to set the selection. Performing this action with no arguments
+ * clears the selection.
+ * <p>
+ * <strong>Arguments:</strong>
+ * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT},
+ * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT}<br>
+ * <strong>Example:</strong>
+ * <code><pre><p>
+ * Bundle arguments = new Bundle();
+ * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1);
+ * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2);
+ * info.performAction(AccessibilityAction.ACTION_SET_SELECTION.getId(), arguments);
+ * </code></pre></p>
+ * </p>
+ *
+ * @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT
+ * @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT
+ */
+ public static final AccessibilityAction ACTION_SET_SELECTION =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_SET_SELECTION, null);
+
+ /**
+ * Action to expand an expandable node.
+ */
+ public static final AccessibilityAction ACTION_EXPAND =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_EXPAND, null);
+
+ /**
+ * Action to collapse an expandable node.
+ */
+ public static final AccessibilityAction ACTION_COLLAPSE =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_COLLAPSE, null);
+
+ /**
+ * Action to dismiss a dismissable node.
+ */
+ public static final AccessibilityAction ACTION_DISMISS =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_DISMISS, null);
+
+ /**
+ * Action that sets the text of the node. Performing the action without argument,
+ * using <code> null</code> or empty {@link CharSequence} will clear the text. This
+ * action will also put the cursor at the end of text.
+ * <p>
+ * <strong>Arguments:</strong>
+ * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br>
+ * <strong>Example:</strong>
+ * <code><pre><p>
+ * Bundle arguments = new Bundle();
+ * arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
+ * "android");
+ * info.performAction(AccessibilityAction.ACTION_SET_TEXT.getId(), arguments);
+ * </code></pre></p>
+ */
+ public static final AccessibilityAction ACTION_SET_TEXT =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_SET_TEXT, null);
+
+ private static final ArraySet<AccessibilityAction> sStandardActions = new ArraySet<AccessibilityAction>();
+ static {
+ sStandardActions.add(ACTION_FOCUS);
+ sStandardActions.add(ACTION_CLEAR_FOCUS);
+ sStandardActions.add(ACTION_SELECT);
+ sStandardActions.add(ACTION_CLEAR_SELECTION);
+ sStandardActions.add(ACTION_CLICK);
+ sStandardActions.add(ACTION_LONG_CLICK);
+ sStandardActions.add(ACTION_ACCESSIBILITY_FOCUS);
+ sStandardActions.add(ACTION_CLEAR_ACCESSIBILITY_FOCUS);
+ sStandardActions.add(ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
+ sStandardActions.add(ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
+ sStandardActions.add(ACTION_NEXT_HTML_ELEMENT);
+ sStandardActions.add(ACTION_PREVIOUS_HTML_ELEMENT);
+ sStandardActions.add(ACTION_SCROLL_FORWARD);
+ sStandardActions.add(ACTION_SCROLL_BACKWARD);
+ sStandardActions.add(ACTION_COPY);
+ sStandardActions.add(ACTION_PASTE);
+ sStandardActions.add(ACTION_CUT);
+ sStandardActions.add(ACTION_SET_SELECTION);
+ sStandardActions.add(ACTION_EXPAND);
+ sStandardActions.add(ACTION_COLLAPSE);
+ sStandardActions.add(ACTION_DISMISS);
+ sStandardActions.add(ACTION_SET_TEXT);
+ }
+
+ private final int mActionId;
+ private final CharSequence mLabel;
+
+ /**
+ * Creates a new AccessibilityAction. For adding a standard action without a specific label,
+ * use the static constants.
+ *
+ * You can also override the description for one the standard actions. Below is an example
+ * how to override the standard click action by adding a custom label:
+ * <pre>
+ * AccessibilityAction action = new AccessibilityAction(
+ * AccessibilityAction.ACTION_ACTION_CLICK, getLocalizedLabel());
+ * node.addAction(action);
+ * </pre>
+ *
+ * @param actionId The id for this action. This should either be one of the
+ * standard actions or a specific action for your app. In that case it is
+ * required to use a resource identifier.
+ * @param label The label for the new AccessibilityAction.
+ */
+ public AccessibilityAction(int actionId, @Nullable CharSequence label) {
+ if ((actionId & ACTION_TYPE_MASK) == 0 && Integer.bitCount(actionId) > 1) {
+ throw new IllegalArgumentException("Invalid standard action id");
+ }
+
+ if ((actionId & STANDARD_NON_LEGACY_ACTION_MASK) != 0) {
+ throw new IllegalArgumentException("action id not a resource id");
}
+
+ mActionId = actionId;
+ mLabel = label;
}
- builder.append("]");
- return builder.toString();
+ /**
+ * Gets the id for this action.
+ *
+ * @return The action id.
+ */
+ public int getId() {
+ return mActionId;
+ }
+
+ /**
+ * Gets the label for this action. Its purpose is to describe the
+ * action to user.
+ *
+ * @return The label.
+ */
+ public CharSequence getLabel() {
+ return mLabel;
+ }
+
+ @Override
+ public int hashCode() {
+ return mActionId;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null) {
+ return false;
+ }
+
+ if (other == this) {
+ return true;
+ }
+
+ if (getClass() != other.getClass()) {
+ return false;
+ }
+
+ return mActionId == ((AccessibilityAction)other).mActionId;
+ }
+
+ @Override
+ public String toString() {
+ return "AccessibilityAction: " + getActionSymbolicName(mActionId) + " - " + mLabel;
+ }
}
/**
diff --git a/core/java/android/webkit/BrowserDownloadListener.java b/core/java/android/webkit/BrowserDownloadListener.java
deleted file mode 100644
index 724cc62..0000000
--- a/core/java/android/webkit/BrowserDownloadListener.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.
- */
-
-package android.webkit;
-
-/**
- * An abstract download listener that allows passing extra information as
- * part of onDownloadStart callback.
- * @hide
- */
-public abstract class BrowserDownloadListener implements DownloadListener {
-
- /**
- * Notify the host application that a file should be downloaded
- * @param url The full url to the content that should be downloaded
- * @param userAgent the user agent to be used for the download.
- * @param contentDisposition Content-disposition http header, if
- * present.
- * @param mimetype The mimetype of the content reported by the server
- * @param referer The referer associated with this url
- * @param contentLength The file size reported by the server
- */
- public abstract void onDownloadStart(String url, String userAgent,
- String contentDisposition, String mimetype, String referer,
- long contentLength);
-
-
- /**
- * Notify the host application that a file should be downloaded
- * @param url The full url to the content that should be downloaded
- * @param userAgent the user agent to be used for the download.
- * @param contentDisposition Content-disposition http header, if
- * present.
- * @param mimetype The mimetype of the content reported by the server
- * @param contentLength The file size reported by the server
- */
- @Override
- public void onDownloadStart(String url, String userAgent,
- String contentDisposition, String mimetype, long contentLength) {
-
- onDownloadStart(url, userAgent, contentDisposition, mimetype, null,
- contentLength);
- }
-}
diff --git a/core/java/android/webkit/WebBackForwardListClient.java b/core/java/android/webkit/WebBackForwardListClient.java
deleted file mode 100644
index 7fe9281..0000000
--- a/core/java/android/webkit/WebBackForwardListClient.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.webkit;
-
-/**
- * Interface to receive notifications when items are added to the
- * {@link WebBackForwardList}.
- * {@hide}
- */
-public abstract class WebBackForwardListClient {
-
- /**
- * Notify the client that <var>item</var> has been added to the
- * WebBackForwardList.
- * @param item The newly created WebHistoryItem
- */
- public void onNewHistoryItem(WebHistoryItem item) { }
-
- /**
- * Notify the client that the <var>item</var> at <var>index</var> is now
- * the current history item.
- * @param item A WebHistoryItem
- * @param index The new history index
- */
- public void onIndexChanged(WebHistoryItem item, int index) { }
-}
diff --git a/core/java/android/widget/RtlSpacingHelper.java b/core/java/android/widget/RtlSpacingHelper.java
new file mode 100644
index 0000000..f6b116f
--- /dev/null
+++ b/core/java/android/widget/RtlSpacingHelper.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 android.widget;
+
+/**
+ * RtlSpacingHelper manages the relationship between left/right and start/end for views
+ * that need to maintain both absolute and relative settings for a form of spacing similar
+ * to view padding.
+ */
+class RtlSpacingHelper {
+ public static final int UNDEFINED = Integer.MIN_VALUE;
+
+ private int mLeft = 0;
+ private int mRight = 0;
+ private int mStart = UNDEFINED;
+ private int mEnd = UNDEFINED;
+ private int mExplicitLeft = 0;
+ private int mExplicitRight = 0;
+
+ private boolean mIsRtl = false;
+ private boolean mIsRelative = false;
+
+ public int getLeft() {
+ return mLeft;
+ }
+
+ public int getRight() {
+ return mRight;
+ }
+
+ public int getStart() {
+ return mIsRtl ? mRight : mLeft;
+ }
+
+ public int getEnd() {
+ return mIsRtl ? mLeft : mRight;
+ }
+
+ public void setRelative(int start, int end) {
+ mStart = start;
+ mEnd = end;
+ mIsRelative = true;
+ if (mIsRtl) {
+ if (end != UNDEFINED) mLeft = end;
+ if (start != UNDEFINED) mRight = start;
+ } else {
+ if (start != UNDEFINED) mLeft = start;
+ if (end != UNDEFINED) mRight = end;
+ }
+ }
+
+ public void setAbsolute(int left, int right) {
+ mIsRelative = false;
+ if (left != UNDEFINED) mLeft = mExplicitLeft = left;
+ if (right != UNDEFINED) mRight = mExplicitRight = right;
+ }
+
+ public void setDirection(boolean isRtl) {
+ if (isRtl == mIsRtl) {
+ return;
+ }
+ mIsRtl = isRtl;
+ if (mIsRelative) {
+ if (isRtl) {
+ mLeft = mEnd != UNDEFINED ? mEnd : mExplicitLeft;
+ mRight = mStart != UNDEFINED ? mStart : mExplicitRight;
+ } else {
+ mLeft = mStart != UNDEFINED ? mStart : mExplicitLeft;
+ mRight = mEnd != UNDEFINED ? mEnd : mExplicitRight;
+ }
+ } else {
+ mLeft = mExplicitLeft;
+ mRight = mExplicitRight;
+ }
+ }
+}
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 928e34e..f903346 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -88,11 +88,14 @@ public class Toolbar extends ViewGroup {
private int mTitleTextAppearance;
private int mSubtitleTextAppearance;
+
private int mTitleMarginStart;
private int mTitleMarginEnd;
private int mTitleMarginTop;
private int mTitleMarginBottom;
+ private final RtlSpacingHelper mContentInsets = new RtlSpacingHelper();
+
private int mGravity = Gravity.START | Gravity.CENTER_VERTICAL;
private CharSequence mTitleText;
@@ -135,8 +138,8 @@ public class Toolbar extends ViewGroup {
mTitleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0);
mSubtitleTextAppearance = a.getResourceId(R.styleable.Toolbar_subtitleTextAppearance, 0);
mGravity = a.getInteger(R.styleable.Toolbar_gravity, mGravity);
- mTitleMarginStart = mTitleMarginEnd = Math.max(0, a.getDimensionPixelOffset(
- R.styleable.Toolbar_titleMargins, -1));
+ mTitleMarginStart = mTitleMarginEnd = mTitleMarginTop = mTitleMarginBottom =
+ a.getDimensionPixelOffset(R.styleable.Toolbar_titleMargins, 0);
final int marginStart = a.getDimensionPixelOffset(R.styleable.Toolbar_titleMarginStart, -1);
if (marginStart >= 0) {
@@ -159,6 +162,24 @@ public class Toolbar extends ViewGroup {
mTitleMarginBottom = marginBottom;
}
+ final int contentInsetStart =
+ a.getDimensionPixelOffset(R.styleable.Toolbar_contentInsetStart,
+ RtlSpacingHelper.UNDEFINED);
+ final int contentInsetEnd =
+ a.getDimensionPixelOffset(R.styleable.Toolbar_contentInsetEnd,
+ RtlSpacingHelper.UNDEFINED);
+ final int contentInsetLeft =
+ a.getDimensionPixelSize(R.styleable.Toolbar_contentInsetLeft, 0);
+ final int contentInsetRight =
+ a.getDimensionPixelSize(R.styleable.Toolbar_contentInsetRight, 0);
+
+ mContentInsets.setAbsolute(contentInsetLeft, contentInsetRight);
+
+ if (contentInsetStart != RtlSpacingHelper.UNDEFINED ||
+ contentInsetEnd != RtlSpacingHelper.UNDEFINED) {
+ mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
+ }
+
final CharSequence title = a.getText(R.styleable.Toolbar_title);
if (!TextUtils.isEmpty(title)) {
setTitle(title);
@@ -171,6 +192,12 @@ public class Toolbar extends ViewGroup {
a.recycle();
}
+ @Override
+ public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) {
+ super.onRtlPropertiesChanged(layoutDirection);
+ mContentInsets.setDirection(layoutDirection == LAYOUT_DIRECTION_RTL);
+ }
+
/**
* Set a logo drawable from a resource id.
*
@@ -489,6 +516,122 @@ public class Toolbar extends ViewGroup {
mOnMenuItemClickListener = listener;
}
+ /**
+ * Set the content insets for this toolbar relative to layout direction.
+ *
+ * <p>The content inset affects the valid area for Toolbar content other than
+ * the navigation button and menu. Insets define the minimum margin for these components
+ * and can be used to effectively align Toolbar content along well-known gridlines.</p>
+ *
+ * @param contentInsetStart Content inset for the toolbar starting edge
+ * @param contentInsetEnd Content inset for the toolbar ending edge
+ *
+ * @see #setContentInsetsAbsolute(int, int)
+ * @see #getContentInsetStart()
+ * @see #getContentInsetEnd()
+ * @see #getContentInsetLeft()
+ * @see #getContentInsetRight()
+ */
+ public void setContentInsetsRelative(int contentInsetStart, int contentInsetEnd) {
+ mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
+ }
+
+ /**
+ * Get the starting content inset for this toolbar.
+ *
+ * <p>The content inset affects the valid area for Toolbar content other than
+ * the navigation button and menu. Insets define the minimum margin for these components
+ * and can be used to effectively align Toolbar content along well-known gridlines.</p>
+ *
+ * @return The starting content inset for this toolbar
+ *
+ * @see #setContentInsetsRelative(int, int)
+ * @see #setContentInsetsAbsolute(int, int)
+ * @see #getContentInsetEnd()
+ * @see #getContentInsetLeft()
+ * @see #getContentInsetRight()
+ */
+ public int getContentInsetStart() {
+ return mContentInsets.getStart();
+ }
+
+ /**
+ * Get the ending content inset for this toolbar.
+ *
+ * <p>The content inset affects the valid area for Toolbar content other than
+ * the navigation button and menu. Insets define the minimum margin for these components
+ * and can be used to effectively align Toolbar content along well-known gridlines.</p>
+ *
+ * @return The ending content inset for this toolbar
+ *
+ * @see #setContentInsetsRelative(int, int)
+ * @see #setContentInsetsAbsolute(int, int)
+ * @see #getContentInsetStart()
+ * @see #getContentInsetLeft()
+ * @see #getContentInsetRight()
+ */
+ public int getContentInsetEnd() {
+ return mContentInsets.getEnd();
+ }
+
+ /**
+ * Set the content insets for this toolbar.
+ *
+ * <p>The content inset affects the valid area for Toolbar content other than
+ * the navigation button and menu. Insets define the minimum margin for these components
+ * and can be used to effectively align Toolbar content along well-known gridlines.</p>
+ *
+ * @param contentInsetLeft Content inset for the toolbar's left edge
+ * @param contentInsetRight Content inset for the toolbar's right edge
+ *
+ * @see #setContentInsetsAbsolute(int, int)
+ * @see #getContentInsetStart()
+ * @see #getContentInsetEnd()
+ * @see #getContentInsetLeft()
+ * @see #getContentInsetRight()
+ */
+ public void setContentInsetsAbsolute(int contentInsetLeft, int contentInsetRight) {
+ mContentInsets.setAbsolute(contentInsetLeft, contentInsetRight);
+ }
+
+ /**
+ * Get the left content inset for this toolbar.
+ *
+ * <p>The content inset affects the valid area for Toolbar content other than
+ * the navigation button and menu. Insets define the minimum margin for these components
+ * and can be used to effectively align Toolbar content along well-known gridlines.</p>
+ *
+ * @return The left content inset for this toolbar
+ *
+ * @see #setContentInsetsRelative(int, int)
+ * @see #setContentInsetsAbsolute(int, int)
+ * @see #getContentInsetStart()
+ * @see #getContentInsetEnd()
+ * @see #getContentInsetRight()
+ */
+ public int getContentInsetLeft() {
+ return mContentInsets.getLeft();
+ }
+
+ /**
+ * Get the right content inset for this toolbar.
+ *
+ * <p>The content inset affects the valid area for Toolbar content other than
+ * the navigation button and menu. Insets define the minimum margin for these components
+ * and can be used to effectively align Toolbar content along well-known gridlines.</p>
+ *
+ * @return The right content inset for this toolbar
+ *
+ * @see #setContentInsetsRelative(int, int)
+ * @see #setContentInsetsAbsolute(int, int)
+ * @see #getContentInsetStart()
+ * @see #getContentInsetEnd()
+ * @see #getContentInsetLeft()
+ */
+ public int getContentInsetRight() {
+ return mContentInsets.getRight();
+ }
+
private void ensureNavButtonView() {
if (mNavButtonView == null) {
mNavButtonView = new ImageButton(getContext(), null, R.attr.borderlessButtonStyle);
@@ -522,22 +665,28 @@ public class Toolbar extends ViewGroup {
// System views measure first.
+ int navWidth = 0;
if (shouldLayout(mNavButtonView)) {
measureChildWithMargins(mNavButtonView, widthMeasureSpec, width, heightMeasureSpec, 0);
- width += mNavButtonView.getMeasuredWidth() + getHorizontalMargins(mNavButtonView);
+ navWidth = mNavButtonView.getMeasuredWidth() + getHorizontalMargins(mNavButtonView);
height = Math.max(height, mNavButtonView.getMeasuredHeight() +
getVerticalMargins(mNavButtonView));
childState = combineMeasuredStates(childState, mNavButtonView.getMeasuredState());
}
+ width += Math.max(getContentInsetStart(), navWidth);
+
+ int menuWidth = 0;
if (shouldLayout(mMenuView)) {
measureChildWithMargins(mMenuView, widthMeasureSpec, width, heightMeasureSpec, 0);
- width += mMenuView.getMeasuredWidth() + getHorizontalMargins(mMenuView);
+ menuWidth = mMenuView.getMeasuredWidth() + getHorizontalMargins(mMenuView);
height = Math.max(height, mMenuView.getMeasuredHeight() +
getVerticalMargins(mMenuView));
childState = combineMeasuredStates(childState, mMenuView.getMeasuredState());
}
+ width += Math.max(getContentInsetEnd(), menuWidth);
+
if (shouldLayout(mLogoView)) {
measureChildWithMargins(mLogoView, widthMeasureSpec, width, heightMeasureSpec, 0);
width += mLogoView.getMeasuredWidth() + getHorizontalMargins(mLogoView);
@@ -627,6 +776,9 @@ public class Toolbar extends ViewGroup {
}
}
+ left = Math.max(left, getContentInsetLeft());
+ right = Math.min(right, width - paddingRight - getContentInsetRight());
+
if (shouldLayout(mLogoView)) {
if (isRtl) {
right = layoutChildRight(mLogoView, right);
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index f23c64f..2b62552 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -30,6 +30,7 @@ import android.media.MediaPlayer.OnInfoListener;
import android.media.Metadata;
import android.media.SubtitleController;
import android.media.SubtitleTrack.RenderingWidget;
+import android.media.TtmlRenderer;
import android.media.WebVttRenderer;
import android.net.Uri;
import android.os.Looper;
@@ -314,6 +315,7 @@ public class VideoView extends SurfaceView
final SubtitleController controller = new SubtitleController(
context, mMediaPlayer.getMediaTimeProvider(), mMediaPlayer);
controller.registerRenderer(new WebVttRenderer(context));
+ controller.registerRenderer(new TtmlRenderer(context));
mMediaPlayer.setSubtitleAnchor(controller, this);
if (mAudioSession != 0) {
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 04547495..0769b08 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -46,14 +46,15 @@ interface IBatteryStats {
void noteStartWakelock(int uid, int pid, String name, String historyName,
int type, boolean unimportantForLogging);
- void noteStopWakelock(int uid, int pid, String name, int type);
+ void noteStopWakelock(int uid, int pid, String name, String historyName, int type);
void noteStartWakelockFromSource(in WorkSource ws, int pid, String name, String historyName,
int type, boolean unimportantForLogging);
- void noteChangeWakelockFromSource(in WorkSource ws, int pid, String name, int type,
- in WorkSource newWs, int newPid, String newName,
+ void noteChangeWakelockFromSource(in WorkSource ws, int pid, String name, String histyoryName,
+ int type, in WorkSource newWs, int newPid, String newName,
String newHistoryName, int newType, boolean newUnimportantForLogging);
- void noteStopWakelockFromSource(in WorkSource ws, int pid, String name, int type);
+ void noteStopWakelockFromSource(in WorkSource ws, int pid, String name, String historyName,
+ int type);
void noteVibratorOn(int uid, long durationMillis);
void noteVibratorOff(int uid);
diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index 66548f0..79a8f44 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -268,7 +268,7 @@ public class WindowDecorActionBar extends ActionBar implements
if (getNavigationMode() == NAVIGATION_MODE_TABS) {
tabScroller.setVisibility(View.VISIBLE);
if (mOverlayLayout != null) {
- mOverlayLayout.requestFitSystemWindows();
+ mOverlayLayout.requestApplyInsets();
}
} else {
tabScroller.setVisibility(View.GONE);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 7bd5b12..956c86d 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -48,7 +48,6 @@ import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
import android.view.Display;
@@ -89,7 +88,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 105 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 106 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -236,6 +235,7 @@ public final class BatteryStatsImpl extends BatteryStats {
int mWakeLockNesting;
boolean mWakeLockImportant;
+ public boolean mRecordAllWakeLocks;
int mScreenState = Display.STATE_UNKNOWN;
StopwatchTimer mScreenOnTimer;
@@ -246,6 +246,9 @@ public final class BatteryStatsImpl extends BatteryStats {
boolean mInteractive;
StopwatchTimer mInteractiveTimer;
+ boolean mLowPowerModeEnabled;
+ StopwatchTimer mLowPowerModeEnabledTimer;
+
boolean mPhoneOn;
StopwatchTimer mPhoneOnTimer;
@@ -2314,6 +2317,14 @@ public final class BatteryStatsImpl extends BatteryStats {
private String mInitialAcquireWakeName;
private int mInitialAcquireWakeUid = -1;
+ public void setRecordAllWakeLocksLocked(boolean enabled) {
+ mRecordAllWakeLocks = enabled;
+ if (!enabled) {
+ // Clear out any existing state.
+ mActiveEvents.removeEvents(HistoryItem.EVENT_WAKE_LOCK);
+ }
+ }
+
public void noteStartWakeLocked(int uid, int pid, String name, String historyName, int type,
boolean unimportantForLogging, long elapsedRealtime, long uptime) {
uid = mapUid(uid);
@@ -2321,27 +2332,33 @@ public final class BatteryStatsImpl extends BatteryStats {
// Only care about partial wake locks, since full wake locks
// will be canceled when the user puts the screen to sleep.
aggregateLastWakeupUptimeLocked(uptime);
+ historyName = historyName == null || mRecordAllWakeLocks ? name : historyName;
if (mWakeLockNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_WAKE_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: "
+ Integer.toHexString(mHistoryCur.states));
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
- mHistoryCur.wakelockTag.string = mInitialAcquireWakeName
- = historyName != null ? historyName : name;
+ mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
mWakeLockImportant = !unimportantForLogging;
addHistoryRecordLocked(elapsedRealtime, uptime);
- } else if (!mWakeLockImportant && !unimportantForLogging) {
+ } else if (!mRecordAllWakeLocks && !mWakeLockImportant && !unimportantForLogging) {
if (mHistoryLastWritten.wakelockTag != null) {
// We'll try to update the last tag.
mHistoryLastWritten.wakelockTag = null;
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
- mHistoryCur.wakelockTag.string = mInitialAcquireWakeName
- = historyName != null ? historyName : name;
+ mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
addHistoryRecordLocked(elapsedRealtime, uptime);
}
mWakeLockImportant = true;
+ } else if (mRecordAllWakeLocks) {
+ if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName,
+ uid, 0)) {
+ return;
+ }
+ addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_WAKE_LOCK_START,
+ historyName, uid);
}
mWakeLockNesting++;
}
@@ -2354,24 +2371,33 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- public void noteStopWakeLocked(int uid, int pid, String name, int type, long elapsedRealtime,
- long uptime) {
+ public void noteStopWakeLocked(int uid, int pid, String name, String historyName, int type,
+ long elapsedRealtime, long uptime) {
uid = mapUid(uid);
if (type == WAKE_TYPE_PARTIAL) {
mWakeLockNesting--;
+ historyName = historyName == null || mRecordAllWakeLocks ? name : historyName;
if (mWakeLockNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: "
+ Integer.toHexString(mHistoryCur.states));
- if ((name != null && !name.equals(mInitialAcquireWakeName))
+ if (mRecordAllWakeLocks
+ || (historyName != null && !historyName.equals(mInitialAcquireWakeName))
|| uid != mInitialAcquireWakeUid) {
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
- mHistoryCur.wakelockTag.string = name;
+ mHistoryCur.wakelockTag.string = historyName;
mHistoryCur.wakelockTag.uid = uid;
}
mInitialAcquireWakeName = null;
mInitialAcquireWakeUid = -1;
addHistoryRecordLocked(elapsedRealtime, uptime);
+ } else if (mRecordAllWakeLocks) {
+ if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName,
+ uid, 0)) {
+ return;
+ }
+ addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_WAKE_LOCK_FINISH,
+ historyName, uid);
}
}
if (uid >= 0) {
@@ -2391,8 +2417,8 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- public void noteChangeWakelockFromSourceLocked(WorkSource ws, int pid, String name, int type,
- WorkSource newWs, int newPid, String newName,
+ public void noteChangeWakelockFromSourceLocked(WorkSource ws, int pid, String name,
+ String historyName, int type, WorkSource newWs, int newPid, String newName,
String newHistoryName, int newType, boolean newUnimportantForLogging) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
@@ -2406,16 +2432,17 @@ public final class BatteryStatsImpl extends BatteryStats {
}
final int NO = ws.size();
for (int i=0; i<NO; i++) {
- noteStopWakeLocked(ws.get(i), pid, name, type, elapsedRealtime, uptime);
+ noteStopWakeLocked(ws.get(i), pid, name, historyName, type, elapsedRealtime, uptime);
}
}
- public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) {
+ public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name,
+ String historyName, int type) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
final int N = ws.size();
for (int i=0; i<N; i++) {
- noteStopWakeLocked(ws.get(i), pid, name, type, elapsedRealtime, uptime);
+ noteStopWakeLocked(ws.get(i), pid, name, historyName, type, elapsedRealtime, uptime);
}
}
@@ -2684,7 +2711,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(elapsedRealtime);
}
- noteStopWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL,
+ noteStopWakeLocked(-1, -1, "screen", "screen", WAKE_TYPE_PARTIAL,
elapsedRealtime, uptime);
updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), true,
@@ -2780,6 +2807,26 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
+ public void noteLowPowerMode(boolean enabled) {
+ if (mLowPowerModeEnabled != enabled) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
+ mLowPowerModeEnabled = enabled;
+ if (enabled) {
+ mHistoryCur.states2 |= HistoryItem.STATE2_LOW_POWER_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Low power mode enabled to: "
+ + Integer.toHexString(mHistoryCur.states2));
+ mLowPowerModeEnabledTimer.startRunningLocked(elapsedRealtime);
+ } else {
+ mHistoryCur.states2 &= ~HistoryItem.STATE2_LOW_POWER_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Low power mode disabled to: "
+ + Integer.toHexString(mHistoryCur.states2));
+ mLowPowerModeEnabledTimer.stopRunningLocked(elapsedRealtime);
+ }
+ addHistoryRecordLocked(elapsedRealtime, uptime);
+ }
+ }
+
public void notePhoneOnLocked() {
if (!mPhoneOn) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -3443,6 +3490,14 @@ public final class BatteryStatsImpl extends BatteryStats {
return mInteractiveTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
+ @Override public long getLowPowerModeEnabledTime(long elapsedRealtimeUs, int which) {
+ return mLowPowerModeEnabledTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
+ }
+
+ @Override public int getLowPowerModeEnabledCount(int which) {
+ return mLowPowerModeEnabledTimer.getCountLocked(which);
+ }
+
@Override public long getPhoneOnTime(long elapsedRealtimeUs, int which) {
return mPhoneOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@@ -5489,7 +5544,8 @@ public final class BatteryStatsImpl extends BatteryStats {
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mOnBatteryTimeBase);
}
- mPhoneOnTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase);
+ mLowPowerModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase);
+ mPhoneOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null,
mOnBatteryTimeBase);
@@ -5508,18 +5564,18 @@ public final class BatteryStatsImpl extends BatteryStats {
mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase);
mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase);
mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase);
- mWifiOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase);
- mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase);
+ mWifiOnTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase);
+ mGlobalWifiRunningTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase);
for (int i=0; i<NUM_WIFI_STATES; i++) {
mWifiStateTimer[i] = new StopwatchTimer(null, -600-i, null, mOnBatteryTimeBase);
}
- mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase);
+ mBluetoothOnTimer = new StopwatchTimer(null, -6, null, mOnBatteryTimeBase);
for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i, null, mOnBatteryTimeBase);
}
- mAudioOnTimer = new StopwatchTimer(null, -6, null, mOnBatteryTimeBase);
- mVideoOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
- mInteractiveTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
+ mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
+ mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
+ mInteractiveTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase);
mOnBattery = mOnBatteryInternal = false;
long uptime = SystemClock.uptimeMillis() * 1000;
long realtime = SystemClock.elapsedRealtime() * 1000;
@@ -5765,6 +5821,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mScreenBrightnessTimer[i].reset(false);
}
mInteractiveTimer.reset(false);
+ mLowPowerModeEnabledTimer.reset(false);
mPhoneOnTimer.reset(false);
mAudioOnTimer.reset(false);
mVideoOnTimer.reset(false);
@@ -6915,6 +6972,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mInteractive = false;
mInteractiveTimer.readSummaryFromParcelLocked(in);
mPhoneOn = false;
+ mLowPowerModeEnabledTimer.readSummaryFromParcelLocked(in);
mPhoneOnTimer.readSummaryFromParcelLocked(in);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
@@ -7169,6 +7227,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
}
mInteractiveTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mLowPowerModeEnabledTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
@@ -7431,7 +7490,8 @@ public final class BatteryStatsImpl extends BatteryStats {
in);
}
mPhoneOn = false;
- mPhoneOnTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+ mLowPowerModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+ mPhoneOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase, in);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i,
null, mOnBatteryTimeBase, in);
@@ -7453,25 +7513,25 @@ public final class BatteryStatsImpl extends BatteryStats {
mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
mWifiOn = false;
- mWifiOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase, in);
+ mWifiOnTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase, in);
mGlobalWifiRunning = false;
- mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase, in);
+ mGlobalWifiRunningTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase, in);
for (int i=0; i<NUM_WIFI_STATES; i++) {
mWifiStateTimer[i] = new StopwatchTimer(null, -600-i,
null, mOnBatteryTimeBase, in);
}
mBluetoothOn = false;
- mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase, in);
+ mBluetoothOnTimer = new StopwatchTimer(null, -6, null, mOnBatteryTimeBase, in);
for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i,
null, mOnBatteryTimeBase, in);
}
mAudioOn = false;
- mAudioOnTimer = new StopwatchTimer(null, -6, null, mOnBatteryTimeBase);
+ mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
mVideoOn = false;
- mVideoOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
+ mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
mInteractive = false;
- mInteractiveTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase, in);
+ mInteractiveTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase, in);
mDischargeUnplugLevel = in.readInt();
mDischargePlugLevel = in.readInt();
mDischargeCurrentLevel = in.readInt();
@@ -7570,6 +7630,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mScreenBrightnessTimer[i].writeToParcel(out, uSecRealtime);
}
mInteractiveTimer.writeToParcel(out, uSecRealtime);
+ mLowPowerModeEnabledTimer.writeToParcel(out, uSecRealtime);
mPhoneOnTimer.writeToParcel(out, uSecRealtime);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
@@ -7688,6 +7749,8 @@ public final class BatteryStatsImpl extends BatteryStats {
}
pr.println("*** Interactive timer:");
mInteractiveTimer.logState(pr, " ");
+ pr.println("*** Low power mode timer:");
+ mLowPowerModeEnabledTimer.logState(pr, " ");
pr.println("*** Phone timer:");
mPhoneOnTimer.logState(pr, " ");
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
diff --git a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
index 772dc5f..841a02a 100644
--- a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
@@ -238,6 +238,10 @@ public class GlowPadView extends View {
Drawable pointDrawable = pointId != 0 ? context.getDrawable(pointId) : null;
mGlowRadius = a.getDimension(R.styleable.GlowPadView_glowRadius, 0.0f);
+ mPointCloud = new PointCloud(pointDrawable);
+ mPointCloud.makePointCloud(mInnerRadius, mOuterRadius);
+ mPointCloud.glowManager.setRadius(mGlowRadius);
+
TypedValue outValue = new TypedValue();
// Read array of target drawables
@@ -273,10 +277,6 @@ public class GlowPadView extends View {
setVibrateEnabled(mVibrationDuration > 0);
assignDefaultsIfNeeded();
-
- mPointCloud = new PointCloud(pointDrawable);
- mPointCloud.makePointCloud(mInnerRadius, mOuterRadius);
- mPointCloud.glowManager.setRadius(mGlowRadius);
}
private int getResourceId(TypedArray a, int id) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 726b2f7..0ad2ab2 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -5,6 +5,7 @@ LOCAL_CFLAGS += -DHAVE_CONFIG_H -DKHTML_NO_EXCEPTIONS -DGKWQ_NO_JAVA
LOCAL_CFLAGS += -DNO_SUPPORT_JS_BINDING -DQT_NO_WHEELEVENT -DKHTML_NO_XBL
LOCAL_CFLAGS += -U__APPLE__
LOCAL_CFLAGS += -Wno-unused-parameter -Wno-int-to-pointer-cast
+LOCAL_CFLAGS += -Wno-non-virtual-dtor
LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
LOCAL_CPPFLAGS += -Wno-conversion-null
@@ -125,6 +126,7 @@ LOCAL_SRC_FILES:= \
android/graphics/Xfermode.cpp \
android/graphics/YuvToJpegEncoder.cpp \
android/graphics/pdf/PdfDocument.cpp \
+ android/graphics/pdf/PdfRenderer.cpp \
android_media_AudioRecord.cpp \
android_media_AudioSystem.cpp \
android_media_AudioTrack.cpp \
@@ -169,6 +171,9 @@ LOCAL_C_INCLUDES += \
$(call include-path-for, libhardware_legacy)/hardware_legacy \
$(TOP)/frameworks/av/include \
$(TOP)/system/media/camera/include \
+ external/pdfrenderer/core/include/fpdfapi \
+ external/pdfrenderer/core/include/fpdfdoc \
+ external/pdfrenderer/fpdfsdk/include \
external/skia/src/core \
external/skia/src/effects \
external/skia/src/images \
@@ -222,6 +227,7 @@ LOCAL_SHARED_LIBRARIES := \
libharfbuzz_ng \
libz \
libaudioutils \
+ libpdfrenderer \
ifeq ($(USE_OPENGL_RENDERER),true)
LOCAL_SHARED_LIBRARIES += libhwui
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f41af04..a4dc824 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -120,6 +120,7 @@ extern int register_android_graphics_Region(JNIEnv* env);
extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
extern int register_android_graphics_Xfermode(JNIEnv* env);
extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
+extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
extern int register_android_view_RenderNode(JNIEnv* env);
extern int register_android_view_RenderNodeAnimator(JNIEnv* env);
@@ -1258,6 +1259,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_graphics_Xfermode),
REG_JNI(register_android_graphics_YuvImage),
REG_JNI(register_android_graphics_pdf_PdfDocument),
+ REG_JNI(register_android_graphics_pdf_PdfRenderer),
REG_JNI(register_android_database_CursorWindow),
REG_JNI(register_android_database_SQLiteConnection),
diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp
index 23af860..cbd20e9 100644
--- a/core/jni/android/graphics/Matrix.cpp
+++ b/core/jni/android/graphics/Matrix.cpp
@@ -50,10 +50,17 @@ public:
SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
return obj->isIdentity() ? JNI_TRUE : JNI_FALSE;
}
+
+ static jboolean isAffine(JNIEnv* env, jobject clazz, jlong objHandle) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ return obj->asAffine(NULL) ? JNI_TRUE : JNI_FALSE;
+ }
+
static jboolean rectStaysRect(JNIEnv* env, jobject clazz, jlong objHandle) {
SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
return obj->rectStaysRect() ? JNI_TRUE : JNI_FALSE;
}
+
static void reset(JNIEnv* env, jobject clazz, jlong objHandle) {
SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
obj->reset();
@@ -302,6 +309,7 @@ static JNINativeMethod methods[] = {
{"finalizer", "(J)V", (void*) SkMatrixGlue::finalizer},
{"native_create","(J)J", (void*) SkMatrixGlue::create},
{"native_isIdentity","(J)Z", (void*) SkMatrixGlue::isIdentity},
+ {"native_isAffine","(J)Z", (void*) SkMatrixGlue::isAffine},
{"native_rectStaysRect","(J)Z", (void*) SkMatrixGlue::rectStaysRect},
{"native_reset","(J)V", (void*) SkMatrixGlue::reset},
{"native_set","(JJ)V", (void*) SkMatrixGlue::set},
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
new file mode 100644
index 0000000..15de24a
--- /dev/null
+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "GraphicsJNI.h"
+#include "SkBitmap.h"
+#include "SkMatrix.h"
+#include "fpdfview.h"
+#include "fsdk_rendercontext.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <vector>
+#include <utils/Log.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android {
+
+static const int RENDER_MODE_FOR_DISPLAY = 1;
+static const int RENDER_MODE_FOR_PRINT = 2;
+
+static struct {
+ jfieldID x;
+ jfieldID y;
+} gPointClassInfo;
+
+static Mutex sLock;
+
+static int sUnmatchedInitRequestCount = 0;
+
+static void initializeLibraryIfNeeded() {
+ Mutex::Autolock _l(sLock);
+ if (sUnmatchedInitRequestCount == 0) {
+ FPDF_InitLibrary(NULL);
+ }
+ sUnmatchedInitRequestCount++;
+}
+
+static void destroyLibraryIfNeeded() {
+ Mutex::Autolock _l(sLock);
+ sUnmatchedInitRequestCount--;
+ if (sUnmatchedInitRequestCount == 0) {
+ FPDF_DestroyLibrary();
+ }
+}
+
+static int getBlock(void* param, unsigned long position, unsigned char* outBuffer,
+ unsigned long size) {
+ const int fd = reinterpret_cast<intptr_t>(param);
+ const int readCount = pread(fd, outBuffer, size, position);
+ if (readCount < 0) {
+ ALOGE("Cannot read from file descriptor. Error:%d", errno);
+ return 0;
+ }
+ return 1;
+}
+
+static jlong nativeCreate(JNIEnv* env, jclass thiz, jint fd, jlong size) {
+ initializeLibraryIfNeeded();
+
+ FPDF_FILEACCESS loader;
+ loader.m_FileLen = size;
+ loader.m_Param = reinterpret_cast<void*>(intptr_t(fd));
+ loader.m_GetBlock = &getBlock;
+
+ FPDF_DOCUMENT document = FPDF_LoadCustomDocument(&loader, NULL);
+
+ if (!document) {
+ const long error = FPDF_GetLastError();
+ jniThrowException(env, "java/io/IOException",
+ "cannot create document. Error:" + error);
+ destroyLibraryIfNeeded();
+ return -1;
+ }
+
+ return reinterpret_cast<jlong>(document);
+}
+
+static jlong nativeOpenPageAndGetSize(JNIEnv* env, jclass thiz, jlong documentPtr,
+ jint pageIndex, jobject outSize) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+ FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
+
+ if (!page) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "cannot load page");
+ return -1;
+ }
+
+ double width = 0;
+ double height = 0;
+
+ const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height);
+
+ if (!result) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "cannot get page size");
+ return -1;
+ }
+
+ env->SetIntField(outSize, gPointClassInfo.x, width);
+ env->SetIntField(outSize, gPointClassInfo.y, height);
+
+ return reinterpret_cast<jlong>(page);
+}
+
+static void nativeClosePage(JNIEnv* env, jclass thiz, jlong pagePtr) {
+ FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
+ FPDF_ClosePage(page);
+}
+
+static void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+ FPDF_CloseDocument(document);
+ destroyLibraryIfNeeded();
+}
+
+static jint nativeGetPageCount(JNIEnv* env, jclass thiz, jlong documentPtr) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+ return FPDF_GetPageCount(document);
+}
+
+static jboolean nativeScaleForPrinting(JNIEnv* env, jclass thiz, jlong documentPtr) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+ return FPDF_VIEWERREF_GetPrintScaling(document);
+}
+
+static void DropContext(void* data) {
+ delete (CRenderContext*) data;
+}
+
+static void renderPageBitmap(FPDF_BITMAP bitmap, FPDF_PAGE page, int destLeft, int destTop,
+ int destRight, int destBottom, SkMatrix* transform, int flags) {
+ // Note: this code ignores the currently unused RENDER_NO_NATIVETEXT,
+ // FPDF_RENDER_LIMITEDIMAGECACHE, FPDF_RENDER_FORCEHALFTONE, FPDF_GRAYSCALE,
+ // and FPDF_ANNOT flags. To add support for that refer to FPDF_RenderPage_Retail
+ // in fpdfview.cpp
+
+ CRenderContext* pContext = FX_NEW CRenderContext;
+
+ CPDF_Page* pPage = (CPDF_Page*) page;
+ pPage->SetPrivateData((void*) 1, pContext, DropContext);
+
+ CFX_FxgeDevice* fxgeDevice = FX_NEW CFX_FxgeDevice;
+ pContext->m_pDevice = fxgeDevice;
+
+ // Reverse the bytes (last argument TRUE) since the Android
+ // format is ARGB while the renderer uses BGRA internally.
+ fxgeDevice->Attach((CFX_DIBitmap*) bitmap, 0, TRUE);
+
+ CPDF_RenderOptions* renderOptions = pContext->m_pOptions;
+
+ if (!renderOptions) {
+ renderOptions = FX_NEW CPDF_RenderOptions;
+ pContext->m_pOptions = renderOptions;
+ }
+
+ if (flags & FPDF_LCD_TEXT) {
+ renderOptions->m_Flags |= RENDER_CLEARTYPE;
+ } else {
+ renderOptions->m_Flags &= ~RENDER_CLEARTYPE;
+ }
+
+ const CPDF_OCContext::UsageType usage = (flags & FPDF_PRINTING)
+ ? CPDF_OCContext::Print : CPDF_OCContext::View;
+
+ renderOptions->m_AddFlags = flags >> 8;
+ renderOptions->m_pOCContext = new CPDF_OCContext(pPage->m_pDocument, usage);
+
+ fxgeDevice->SaveState();
+
+ FX_RECT clip;
+ clip.left = destLeft;
+ clip.right = destRight;
+ clip.top = destTop;
+ clip.bottom = destBottom;
+ fxgeDevice->SetClip_Rect(&clip);
+
+ CPDF_RenderContext* pageContext = FX_NEW CPDF_RenderContext;
+ pContext->m_pContext = pageContext;
+ pageContext->Create(pPage);
+
+ CFX_AffineMatrix matrix;
+ if (!transform) {
+ pPage->GetDisplayMatrix(matrix, destLeft, destTop, destRight - destLeft,
+ destBottom - destTop, 0);
+ } else {
+ // PDF's coordinate system origin is left-bottom while
+ // in graphics it is the top-left, so remap the origin.
+ matrix.Set(1, 0, 0, -1, 0, pPage->GetPageHeight());
+ matrix.Scale(transform->getScaleX(), transform->getScaleY());
+ matrix.Rotate(transform->getSkewX(), transform->getSkewY());
+ matrix.Translate(transform->getTranslateX(), transform->getTranslateY());
+ }
+ pageContext->AppendObjectList(pPage, &matrix);
+
+ pContext->m_pRenderer = FX_NEW CPDF_ProgressiveRenderer;
+ pContext->m_pRenderer->Start(pageContext, fxgeDevice, renderOptions, NULL);
+
+ fxgeDevice->RestoreState();
+
+ pPage->RemovePrivateData((void*) 1);
+
+ delete pContext;
+}
+
+static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong pagePtr,
+ jlong bitmapPtr, jint destLeft, jint destTop, jint destRight, jint destBottom,
+ jlong matrixPtr, jint renderMode) {
+
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+ FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
+ SkBitmap* skBitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
+ SkMatrix* skMatrix = reinterpret_cast<SkMatrix*>(matrixPtr);
+
+ skBitmap->lockPixels();
+
+ const int stride = skBitmap->width() * 4;
+
+ FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(skBitmap->width(), skBitmap->height(),
+ FPDFBitmap_BGRA, skBitmap->getPixels(), stride);
+
+ if (!bitmap) {
+ ALOGE("Erorr creating bitmap");
+ return;
+ }
+
+ int renderFlags = 0;
+ if (renderMode == RENDER_MODE_FOR_DISPLAY) {
+ renderFlags |= FPDF_LCD_TEXT;
+ } else if (renderMode == RENDER_MODE_FOR_PRINT) {
+ renderFlags |= FPDF_PRINTING;
+ }
+
+ renderPageBitmap(bitmap, page, destLeft, destTop, destRight,
+ destBottom, skMatrix, renderFlags);
+
+ skBitmap->unlockPixels();
+}
+
+static JNINativeMethod gPdfRenderer_Methods[] = {
+ {"nativeCreate", "(IJ)J", (void*) nativeCreate},
+ {"nativeClose", "(J)V", (void*) nativeClose},
+ {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
+ {"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting},
+ {"nativeRenderPage", "(JJJIIIIJI)V", (void*) nativeRenderPage},
+ {"nativeOpenPageAndGetSize", "(JILandroid/graphics/Point;)J", (void*) nativeOpenPageAndGetSize},
+ {"nativeClosePage", "(J)V", (void*) nativeClosePage}
+};
+
+int register_android_graphics_pdf_PdfRenderer(JNIEnv* env) {
+ int result = android::AndroidRuntime::registerNativeMethods(
+ env, "android/graphics/pdf/PdfRenderer", gPdfRenderer_Methods,
+ NELEM(gPdfRenderer_Methods));
+
+ jclass clazz = env->FindClass("android/graphics/Point");
+ gPointClassInfo.x = env->GetFieldID(clazz, "x", "I");
+ gPointClassInfo.y = env->GetFieldID(clazz, "y", "I");
+
+ return result;
+};
+
+};
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 662af89..d82fc96 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -697,6 +697,38 @@ void signalExceptionForError(JNIEnv* env, jobject obj, status_t err,
jniThrowException(env, "java/lang/RuntimeException",
"Not allowed to write file descriptors here");
break;
+ case -EBADF:
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Bad file descriptor");
+ break;
+ case -ENFILE:
+ jniThrowException(env, "java/lang/RuntimeException",
+ "File table overflow");
+ break;
+ case -EMFILE:
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Too many open files");
+ break;
+ case -EFBIG:
+ jniThrowException(env, "java/lang/RuntimeException",
+ "File too large");
+ break;
+ case -ENOSPC:
+ jniThrowException(env, "java/lang/RuntimeException",
+ "No space left on device");
+ break;
+ case -ESPIPE:
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Illegal seek");
+ break;
+ case -EROFS:
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Read-only file system");
+ break;
+ case -EMLINK:
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Too many links");
+ break;
default:
ALOGE("Unknown binder error code. 0x%" PRIx32, err);
String8 msg;
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 50eb869..27d3f39 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -686,8 +686,8 @@ static void renderTextLayout(OpenGLRenderer* renderer, Layout* layout,
MinikinFontSkia* mfs = static_cast<MinikinFontSkia *>(layout->getFont(i));
skFace = mfs->GetSkTypeface();
glyphs[i] = layout->getGlyphId(i);
- pos[2 * i] = SkFloatToScalar(layout->getX(i));
- pos[2 * i + 1] = SkFloatToScalar(layout->getY(i));
+ pos[2 * i] = layout->getX(i);
+ pos[2 * i + 1] = layout->getY(i);
if (i > 0 && skFace != lastFace) {
paint->setTypeface(lastFace);
size_t glyphsCount = i - start;
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index e45a901..867c1b1 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -80,6 +80,7 @@ static void android_view_RenderNode_setCaching(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jboolean caching) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setCaching(caching);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setStaticMatrix(JNIEnv* env,
@@ -87,6 +88,7 @@ static void android_view_RenderNode_setStaticMatrix(JNIEnv* env,
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
renderNode->mutateStagingProperties().setStaticMatrix(matrix);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setAnimationMatrix(JNIEnv* env,
@@ -94,24 +96,28 @@ static void android_view_RenderNode_setAnimationMatrix(JNIEnv* env,
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
renderNode->mutateStagingProperties().setAnimationMatrix(matrix);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setClipToBounds(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jboolean clipToBounds) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setClipToBounds(clipToBounds);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setProjectBackwards(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jboolean shouldProject) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setProjectBackwards(shouldProject);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setProjectionReceiver(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jboolean shouldRecieve) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setProjectionReceiver(shouldRecieve);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setOutlineRoundRect(JNIEnv* env,
@@ -119,6 +125,7 @@ static void android_view_RenderNode_setOutlineRoundRect(JNIEnv* env,
jint right, jint bottom, jfloat radius) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().mutableOutline().setRoundRect(left, top, right, bottom, radius);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setOutlineConvexPath(JNIEnv* env,
@@ -126,18 +133,21 @@ static void android_view_RenderNode_setOutlineConvexPath(JNIEnv* env,
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
SkPath* outlinePath = reinterpret_cast<SkPath*>(outlinePathPtr);
renderNode->mutateStagingProperties().mutableOutline().setConvexPath(outlinePath);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setOutlineEmpty(JNIEnv* env,
jobject clazz, jlong renderNodePtr) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().mutableOutline().setEmpty();
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setClipToOutline(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jboolean clipToOutline) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().mutableOutline().setShouldClip(clipToOutline);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setRevealClip(JNIEnv* env,
@@ -146,114 +156,133 @@ static void android_view_RenderNode_setRevealClip(JNIEnv* env,
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().mutableRevealClip().set(
shouldClip, inverseClip, x, y, radius);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setAlpha(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float alpha) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setAlpha(alpha);
+ renderNode->setPropertyFieldsDirty(RenderNode::ALPHA);
}
static void android_view_RenderNode_setHasOverlappingRendering(JNIEnv* env,
jobject clazz, jlong renderNodePtr, bool hasOverlappingRendering) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setHasOverlappingRendering(hasOverlappingRendering);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setElevation(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float elevation) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setElevation(elevation);
+ renderNode->setPropertyFieldsDirty(RenderNode::Z);
}
static void android_view_RenderNode_setTranslationX(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float tx) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setTranslationX(tx);
+ renderNode->setPropertyFieldsDirty(RenderNode::TRANSLATION_X | RenderNode::X);
}
static void android_view_RenderNode_setTranslationY(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float ty) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setTranslationY(ty);
+ renderNode->setPropertyFieldsDirty(RenderNode::TRANSLATION_Y | RenderNode::Y);
}
static void android_view_RenderNode_setTranslationZ(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float tz) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setTranslationZ(tz);
+ renderNode->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z | RenderNode::Z);
}
static void android_view_RenderNode_setRotation(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float rotation) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setRotation(rotation);
+ renderNode->setPropertyFieldsDirty(RenderNode::ROTATION);
}
static void android_view_RenderNode_setRotationX(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float rx) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setRotationX(rx);
+ renderNode->setPropertyFieldsDirty(RenderNode::ROTATION_X);
}
static void android_view_RenderNode_setRotationY(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float ry) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setRotationY(ry);
+ renderNode->setPropertyFieldsDirty(RenderNode::ROTATION_Y);
}
static void android_view_RenderNode_setScaleX(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float sx) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setScaleX(sx);
+ renderNode->setPropertyFieldsDirty(RenderNode::SCALE_X);
}
static void android_view_RenderNode_setScaleY(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float sy) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setScaleY(sy);
+ renderNode->setPropertyFieldsDirty(RenderNode::SCALE_Y);
}
static void android_view_RenderNode_setPivotX(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float px) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setPivotX(px);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setPivotY(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float py) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setPivotY(py);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setCameraDistance(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float distance) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setCameraDistance(distance);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setLeft(JNIEnv* env,
jobject clazz, jlong renderNodePtr, int left) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setLeft(left);
+ renderNode->setPropertyFieldsDirty(RenderNode::X);
}
static void android_view_RenderNode_setTop(JNIEnv* env,
jobject clazz, jlong renderNodePtr, int top) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setTop(top);
+ renderNode->setPropertyFieldsDirty(RenderNode::Y);
}
static void android_view_RenderNode_setRight(JNIEnv* env,
jobject clazz, jlong renderNodePtr, int right) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setRight(right);
+ renderNode->setPropertyFieldsDirty(RenderNode::X);
}
static void android_view_RenderNode_setBottom(JNIEnv* env,
jobject clazz, jlong renderNodePtr, int bottom) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setBottom(bottom);
+ renderNode->setPropertyFieldsDirty(RenderNode::Y);
}
static void android_view_RenderNode_setLeftTopRightBottom(JNIEnv* env,
@@ -261,18 +290,21 @@ static void android_view_RenderNode_setLeftTopRightBottom(JNIEnv* env,
int right, int bottom) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setLeftTopRightBottom(left, top, right, bottom);
+ renderNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
}
static void android_view_RenderNode_offsetLeftAndRight(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float offset) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().offsetLeftRight(offset);
+ renderNode->setPropertyFieldsDirty(RenderNode::X);
}
static void android_view_RenderNode_offsetTopAndBottom(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float offset) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().offsetTopBottom(offset);
+ renderNode->setPropertyFieldsDirty(RenderNode::Y);
}
// ----------------------------------------------------------------------------
@@ -285,6 +317,12 @@ static jboolean android_view_RenderNode_hasOverlappingRendering(JNIEnv* env,
return renderNode->stagingProperties().hasOverlappingRendering();
}
+static jboolean android_view_RenderNode_getClipToOutline(JNIEnv* env,
+ jobject clazz, jlong renderNodePtr) {
+ RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+ return renderNode->stagingProperties().getOutline().getShouldClip();
+}
+
static jfloat android_view_RenderNode_getAlpha(JNIEnv* env,
jobject clazz, jlong renderNodePtr) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
@@ -505,6 +543,7 @@ static JNINativeMethod gMethods[] = {
{ "nOffsetTopAndBottom", "(JF)V", (void*) android_view_RenderNode_offsetTopAndBottom },
{ "nHasOverlappingRendering", "(J)Z", (void*) android_view_RenderNode_hasOverlappingRendering },
+ { "nGetClipToOutline", "(J)Z", (void*) android_view_RenderNode_getClipToOutline },
{ "nGetAlpha", "(J)F", (void*) android_view_RenderNode_getAlpha },
{ "nGetLeft", "(J)F", (void*) android_view_RenderNode_getLeft },
{ "nGetTop", "(J)F", (void*) android_view_RenderNode_getTop },
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index 5733f60..ea2f96e 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -62,7 +62,7 @@ public:
mWeakThis = NULL;
}
- virtual void onAnimationFinished(BaseAnimator*) {
+ virtual void onAnimationFinished(BaseRenderNodeAnimator*) {
JNIEnv* env = getEnv(mJvm);
env->CallStaticVoidMethod(
gRenderNodeAnimatorClassInfo.clazz,
@@ -81,13 +81,6 @@ static inline RenderPropertyAnimator::RenderProperty toRenderProperty(jint prope
return static_cast<RenderPropertyAnimator::RenderProperty>(property);
}
-static inline RenderPropertyAnimator::DeltaValueType toDeltaType(jint deltaType) {
- LOG_ALWAYS_FATAL_IF(deltaType != RenderPropertyAnimator::DELTA
- && deltaType != RenderPropertyAnimator::ABSOLUTE,
- "Invalid delta type %d", deltaType);
- return static_cast<RenderPropertyAnimator::DeltaValueType>(deltaType);
-}
-
static inline CanvasPropertyPaintAnimator::PaintField toPaintField(jint field) {
LOG_ALWAYS_FATAL_IF(field < 0
|| field > CanvasPropertyPaintAnimator::ALPHA,
@@ -96,49 +89,46 @@ static inline CanvasPropertyPaintAnimator::PaintField toPaintField(jint field) {
}
static jlong createAnimator(JNIEnv* env, jobject clazz, jobject weakThis,
- jint propertyRaw, jint deltaTypeRaw, jfloat deltaValue) {
+ jint propertyRaw, jfloat finalValue) {
RenderPropertyAnimator::RenderProperty property = toRenderProperty(propertyRaw);
- RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw);
- BaseAnimator* animator = new RenderPropertyAnimator(property, deltaType, deltaValue);
+ BaseRenderNodeAnimator* animator = new RenderPropertyAnimator(property, finalValue);
animator->setListener(new AnimationListenerBridge(env, weakThis));
return reinterpret_cast<jlong>( animator );
}
static jlong createCanvasPropertyFloatAnimator(JNIEnv* env, jobject clazz,
- jobject weakThis, jlong canvasPropertyPtr, jint deltaTypeRaw, jfloat deltaValue) {
- RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw);
+ jobject weakThis, jlong canvasPropertyPtr, jfloat finalValue) {
CanvasPropertyPrimitive* canvasProperty = reinterpret_cast<CanvasPropertyPrimitive*>(canvasPropertyPtr);
- BaseAnimator* animator = new CanvasPropertyPrimitiveAnimator(canvasProperty, deltaType, deltaValue);
+ BaseRenderNodeAnimator* animator = new CanvasPropertyPrimitiveAnimator(canvasProperty, finalValue);
animator->setListener(new AnimationListenerBridge(env, weakThis));
return reinterpret_cast<jlong>( animator );
}
static jlong createCanvasPropertyPaintAnimator(JNIEnv* env, jobject clazz,
jobject weakThis, jlong canvasPropertyPtr, jint paintFieldRaw,
- jint deltaTypeRaw, jfloat deltaValue) {
- RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw);
+ jfloat finalValue) {
CanvasPropertyPaint* canvasProperty = reinterpret_cast<CanvasPropertyPaint*>(canvasPropertyPtr);
CanvasPropertyPaintAnimator::PaintField paintField = toPaintField(paintFieldRaw);
- BaseAnimator* animator = new CanvasPropertyPaintAnimator(
- canvasProperty, paintField, deltaType, deltaValue);
+ BaseRenderNodeAnimator* animator = new CanvasPropertyPaintAnimator(
+ canvasProperty, paintField, finalValue);
animator->setListener(new AnimationListenerBridge(env, weakThis));
return reinterpret_cast<jlong>( animator );
}
static void setDuration(JNIEnv* env, jobject clazz, jlong animatorPtr, jint duration) {
LOG_ALWAYS_FATAL_IF(duration < 0, "Duration cannot be negative");
- BaseAnimator* animator = reinterpret_cast<BaseAnimator*>(animatorPtr);
+ BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
animator->setDuration(duration);
}
static jint getDuration(JNIEnv* env, jobject clazz, jlong animatorPtr) {
- BaseAnimator* animator = reinterpret_cast<BaseAnimator*>(animatorPtr);
+ BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
return static_cast<jint>(animator->duration());
}
static void setInterpolator(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong interpolatorPtr) {
- BaseAnimator* animator = reinterpret_cast<BaseAnimator*>(animatorPtr);
+ BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
Interpolator* interpolator = reinterpret_cast<Interpolator*>(interpolatorPtr);
animator->setInterpolator(interpolator);
}
@@ -153,9 +143,9 @@ const char* const kClassPathName = "android/view/RenderNodeAnimator";
static JNINativeMethod gMethods[] = {
#ifdef USE_OPENGL_RENDERER
- { "nCreateAnimator", "(Ljava/lang/ref/WeakReference;IIF)J", (void*) createAnimator },
- { "nCreateCanvasPropertyFloatAnimator", "(Ljava/lang/ref/WeakReference;JIF)J", (void*) createCanvasPropertyFloatAnimator },
- { "nCreateCanvasPropertyPaintAnimator", "(Ljava/lang/ref/WeakReference;JIIF)J", (void*) createCanvasPropertyPaintAnimator },
+ { "nCreateAnimator", "(Ljava/lang/ref/WeakReference;IF)J", (void*) createAnimator },
+ { "nCreateCanvasPropertyFloatAnimator", "(Ljava/lang/ref/WeakReference;JF)J", (void*) createCanvasPropertyFloatAnimator },
+ { "nCreateCanvasPropertyPaintAnimator", "(Ljava/lang/ref/WeakReference;JIF)J", (void*) createCanvasPropertyPaintAnimator },
{ "nSetDuration", "(JI)V", (void*) setDuration },
{ "nGetDuration", "(J)I", (void*) getDuration },
{ "nSetInterpolator", "(JJ)V", (void*) setInterpolator },
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index d130a6d..2c10212 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -92,9 +92,9 @@ private:
class OnFinishedEvent {
public:
- OnFinishedEvent(BaseAnimator* animator, AnimationListener* listener)
+ OnFinishedEvent(BaseRenderNodeAnimator* animator, AnimationListener* listener)
: animator(animator), listener(listener) {}
- sp<BaseAnimator> animator;
+ sp<BaseRenderNodeAnimator> animator;
sp<AnimationListener> listener;
};
@@ -127,7 +127,7 @@ public:
virtual ~RootRenderNode() {}
- virtual void callOnFinished(BaseAnimator* animator, AnimationListener* listener) {
+ virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) {
OnFinishedEvent event(animator, listener);
mOnFinishedEvents.push_back(event);
}
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 44e258d..8d82a17 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -21,9 +21,8 @@
for watch products. Do not translate. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Only show power and settings items due to smaller real estate. -->
+ <!-- Only show settings item due to smaller real estate. -->
<string-array translatable="false" name="config_globalActionsList">
- <item>power</item>
<item>settings</item>
</string-array>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 327f6cf..ac75b38 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -657,7 +657,9 @@
<attr name="popupMenuStyle" format="reference" />
<!-- Default StackView style. -->
<attr name="stackViewStyle" format="reference" />
- <!-- Default style for the FragmentBreadCrumbs widget. -->
+
+ <!-- Default style for the FragmentBreadCrumbs widget. This widget is deprecated
+ starting in API level 21 ({@link android.os.Build.VERSION_CODES#.L}). -->
<attr name="fragmentBreadCrumbsStyle" format="reference" />
<!-- NumberPicker style. -->
@@ -1775,6 +1777,35 @@
finishes. Corresponds to
{@link android.view.Window#setAllowExitTransitionOverlap(boolean)}. -->
<attr name="windowAllowExitTransitionOverlap"/>
+
+ <!-- Flag indicating whether this Window is responsible for drawing the background for the
+ system bars. If true and the window is not floating, the system bars are drawn with a
+ transparent background and the corresponding areas in this window are filled with the
+ colors specified in {@link android.R.attr#statusBarColor} and
+ {@link android.R.attr#navigationBarColor}. Corresponds to
+ {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS}. -->
+ <attr name="windowDrawsSystemBarBackgrounds" format="boolean" />
+
+ <!-- The color for the status bar. If the color is not opaque, consider setting
+ {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
+ {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
+ For this to take effect, the window must be drawing the system bar backgrounds with
+ {@link android.R.attr#windowDrawsSystemBarBackgrounds} and the status bar must not
+ have been requested to be translucent with
+ {@link android.R.attr#windowTranslucentStatus}.
+ Corresponds to {@link android.view.Window#setStatusBarColor(int)}. -->
+ <attr name="statusBarColor" format="color" />
+
+ <!-- The color for the navigation bar. If the color is not opaque, consider setting
+ {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
+ {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
+ For this to take effect, the window must be drawing the system bar backgrounds with
+ {@link android.R.attr#windowDrawsSystemBarBackgrounds} and the navigation bar must not
+ have been requested to be translucent with
+ {@link android.R.attr#windowTranslucentNavigation}.
+ Corresponds to {@link android.view.Window#setNavigationBarColor(int)}. -->
+ <attr name="navigationBarColor" format="color" />
+
</declare-styleable>
<!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -2477,7 +2508,7 @@
when doing an Activity transition. Typically, the elements inside a
ViewGroup are each transitioned from the scene individually. The default
for a ViewGroup is false unless it has a background. See
- {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
+ {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.app.Activity,
android.view.View, String)} for more information. Corresponds to
{@link android.view.ViewGroup#setTransitionGroup(boolean)}.-->
<attr name="transitionGroup" format="boolean" />
@@ -4989,6 +5020,15 @@
<attr name="startDelay" format="integer" />
<!-- Interpolator to be used in the animations spawned by this transition. -->
<attr name="interpolator" />
+ <!-- The match order to use for the transition. This is a comma-separated
+ list of values, containing one or more of the following:
+ id, itemId, viewName, instance. These correspond to
+ {@link android.transition.Transition#MATCH_ID},
+ {@link android.transition.Transition#MATCH_ITEM_ID},
+ {@link android.transition.Transition#MATCH_VIEW_NAME}, and
+ {@link android.transition.Transition#MATCH_INSTANCE}, respectively.
+ This corresponds to {@link android.transition.Transition#setMatchOrder(int...)}. -->
+ <attr name="matchOrder" format="string" />
</declare-styleable>
<!-- Use <code>fade</code>as the root tag of the XML resource that
@@ -6617,6 +6657,10 @@
<attr name="titleMarginEnd" format="dimension" />
<attr name="titleMarginTop" format="dimension" />
<attr name="titleMarginBottom" format="dimension" />
+ <attr name="contentInsetStart" format="dimension" />
+ <attr name="contentInsetEnd" format="dimension" />
+ <attr name="contentInsetLeft" format="dimension" />
+ <attr name="contentInsetRight" format="dimension" />
</declare-styleable>
<declare-styleable name="Toolbar_LayoutParams">
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 90ffe8e..44b25f2b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2104,7 +2104,6 @@
<public-padding type="attr" name="l_resource_pad" end="0x1010410" />
- <public type="attr" name="fragmentBreadCrumbsStyle" />
<public type="attr" name="fastScrollStyle" />
<public type="attr" name="windowContentTransitions" />
<public type="attr" name="windowContentTransitionManager" />
@@ -2170,6 +2169,14 @@
<public type="attr" name="splitTrack" />
<public type="attr" name="targetViewName" />
<public type="attr" name="excludeViewName" />
+ <public type="attr" name="matchOrder" />
+ <public type="attr" name="windowDrawsSystemBarBackgrounds" />
+ <public type="attr" name="statusBarColor"/>
+ <public type="attr" name="navigationBarColor"/>
+ <public type="attr" name="contentInsetStart" />
+ <public type="attr" name="contentInsetEnd" />
+ <public type="attr" name="contentInsetLeft" />
+ <public type="attr" name="contentInsetRight" />
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
@@ -2187,20 +2194,16 @@
<public type="style" name="Widget.StackView" />
<public type="style" name="Widget.Holo.FastScroll" />
- <public type="style" name="Widget.Holo.FragmentBreadCrumbs" />
<public type="style" name="Widget.Holo.StackView" />
<public type="style" name="Widget.Holo.Light.Button.Borderless" />
<public type="style" name="Widget.Holo.Light.FastScroll" />
- <public type="style" name="Widget.Holo.Light.FragmentBreadCrumbs" />
<public type="style" name="Widget.Holo.Light.StackView" />
<public type="style" name="Widget.DeviceDefault.FastScroll" />
- <public type="style" name="Widget.DeviceDefault.FragmentBreadCrumbs" />
<public type="style" name="Widget.DeviceDefault.StackView" />
<public type="style" name="Widget.DeviceDefault.Light.FastScroll" />
- <public type="style" name="Widget.DeviceDefault.Light.FragmentBreadCrumbs" />
<public type="style" name="Widget.DeviceDefault.Light.StackView" />
<public type="style" name="TextAppearance.Quantum" />
@@ -2305,7 +2308,6 @@
<public type="style" name="Widget.Quantum.EditText" />
<public type="style" name="Widget.Quantum.ExpandableListView" />
<public type="style" name="Widget.Quantum.FastScroll" />
- <public type="style" name="Widget.Quantum.FragmentBreadCrumbs" />
<public type="style" name="Widget.Quantum.GridView" />
<public type="style" name="Widget.Quantum.HorizontalScrollView" />
<public type="style" name="Widget.Quantum.ImageButton" />
@@ -2365,7 +2367,6 @@
<public type="style" name="Widget.Quantum.Light.EditText" />
<public type="style" name="Widget.Quantum.Light.ExpandableListView" />
<public type="style" name="Widget.Quantum.Light.FastScroll" />
- <public type="style" name="Widget.Quantum.Light.FragmentBreadCrumbs" />
<public type="style" name="Widget.Quantum.Light.GridView" />
<public type="style" name="Widget.Quantum.Light.HorizontalScrollView" />
<public type="style" name="Widget.Quantum.Light.ImageButton" />
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 60e06ce..609a0f3 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -91,7 +91,8 @@ easier.
<style name="Widget.DeviceDefault.CompoundButton.Switch" parent="Widget.Quantum.CompoundButton.Switch"/>
<style name="Widget.DeviceDefault.ExpandableListView.White" parent="Widget.Quantum.ExpandableListView.White"/>
<style name="Widget.DeviceDefault.FastScroll" parent="Widget.Quantum.FastScroll"/>
- <style name="Widget.DeviceDefault.FragmentBreadCrumbs" parent="Widget.Quantum.FragmentBreadCrumbs"/>
+ <!-- The FragmentBreadCrumbs widget is deprecated starting in API level 21 ({@link android.os.Build.VERSION_CODES#.L}). -->
+ <style name="Widget.DeviceDefault.FragmentBreadCrumbs" parent="Widget.Holo.FragmentBreadCrumbs"/>
<style name="Widget.DeviceDefault.Gallery" parent="Widget.Quantum.Gallery"/>
<style name="Widget.DeviceDefault.GestureOverlayView" parent="Widget.Quantum.GestureOverlayView"/>
<style name="Widget.DeviceDefault.ImageWell" parent="Widget.Quantum.ImageWell"/>
@@ -130,7 +131,8 @@ easier.
<style name="Widget.DeviceDefault.Light.EditText" parent="Widget.Quantum.Light.EditText"/>
<style name="Widget.DeviceDefault.Light.ExpandableListView" parent="Widget.Quantum.Light.ExpandableListView"/>
<style name="Widget.DeviceDefault.Light.FastScroll" parent="Widget.Quantum.Light.FastScroll"/>
- <style name="Widget.DeviceDefault.Light.FragmentBreadCrumbs" parent="Widget.Quantum.Light.FragmentBreadCrumbs"/>
+ <!-- The FragmentBreadCrumbs widget is deprecated starting in API level 21 ({@link android.os.Build.VERSION_CODES#.L}). -->
+ <style name="Widget.DeviceDefault.Light.FragmentBreadCrumbs" parent="Widget.Holo.Light.FragmentBreadCrumbs"/>
<style name="Widget.DeviceDefault.Light.GridView" parent="Widget.Quantum.Light.GridView"/>
<style name="Widget.DeviceDefault.Light.ImageButton" parent="Widget.Quantum.Light.ImageButton"/>
<style name="Widget.DeviceDefault.Light.ListView" parent="Widget.Quantum.Light.ListView"/>
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index e693673..a49b89a 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -474,7 +474,6 @@ please see styles_device_defaults.xml.
</style>
<style name="Widget.Quantum.ExpandableListView.White"/>
- <style name="Widget.Quantum.FragmentBreadCrumbs" parent="Widget.FragmentBreadCrumbs"/>
<style name="Widget.Quantum.Gallery" parent="Widget.Gallery"/>
<style name="Widget.Quantum.GestureOverlayView" parent="Widget.GestureOverlayView"/>
<style name="Widget.Quantum.GridView" parent="Widget.GridView"/>
@@ -820,7 +819,6 @@ please see styles_device_defaults.xml.
<style name="Widget.Quantum.Light.EditText" parent="Widget.Quantum.EditText"/>
<style name="Widget.Quantum.Light.ExpandableListView" parent="Widget.Quantum.ExpandableListView"/>
<style name="Widget.Quantum.Light.ExpandableListView.White" parent="Widget.Quantum.ExpandableListView.White"/>
- <style name="Widget.Quantum.Light.FragmentBreadCrumbs" parent="Widget.Quantum.FragmentBreadCrumbs"/>
<style name="Widget.Quantum.Light.Gallery" parent="Widget.Quantum.Gallery"/>
<style name="Widget.Quantum.Light.GestureOverlayView" parent="Widget.Quantum.GestureOverlayView"/>
<style name="Widget.Quantum.Light.GridView" parent="Widget.Quantum.GridView"/>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 1d9bbae..743ad61 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -189,6 +189,9 @@ please see themes_device_defaults.xml.
<item name="windowCloseOnTouchOutside">false</item>
<item name="windowTranslucentStatus">false</item>
<item name="windowTranslucentNavigation">false</item>
+ <item name="windowDrawsSystemBarBackgrounds">false</item>
+ <item name="statusBarColor">@android:color/black</item>
+ <item name="navigationBarColor">@android:color/black</item>
<!-- Define these here; ContextThemeWrappers around themes that define them should
always clear these values. -->
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index f45fbac..e7cf9da 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -161,6 +161,9 @@ please see themes_device_defaults.xml.
<item name="windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
<item name="windowActionBar">true</item>
<item name="windowActionModeOverlay">false</item>
+ <item name="windowDrawsSystemBarBackgrounds">true</item>
+ <item name="statusBarColor">?attr/colorPrimaryDark</item>
+ <item name="navigationBarColor">?attr/colorPrimaryDark</item>
<!-- Dialog attributes -->
<item name="dialogTheme">@style/Theme.Quantum.Dialog</item>
@@ -266,7 +269,6 @@ please see themes_device_defaults.xml.
<item name="popupMenuStyle">@style/Widget.Quantum.PopupMenu</item>
<item name="stackViewStyle">@style/Widget.Quantum.StackView</item>
<item name="activityChooserViewStyle">@style/Widget.Quantum.ActivityChooserView</item>
- <item name="fragmentBreadCrumbsStyle">@style/Widget.Quantum.FragmentBreadCrumbs</item>
<!-- Preference styles -->
<item name="preferenceScreenStyle">@style/Preference.Quantum.PreferenceScreen</item>
@@ -501,6 +503,9 @@ please see themes_device_defaults.xml.
<item name="windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
<item name="windowActionBar">true</item>
<item name="windowActionModeOverlay">false</item>
+ <item name="windowDrawsSystemBarBackgrounds">true</item>
+ <item name="statusBarColor">?attr/colorPrimaryDark</item>
+ <item name="navigationBarColor">?attr/colorPrimaryDark</item>
<!-- Dialog attributes -->
<item name="dialogTheme">@style/Theme.Quantum.Light.Dialog</item>
@@ -606,7 +611,6 @@ please see themes_device_defaults.xml.
<item name="popupMenuStyle">@style/Widget.Quantum.Light.PopupMenu</item>
<item name="stackViewStyle">@style/Widget.Quantum.Light.StackView</item>
<item name="activityChooserViewStyle">@style/Widget.Quantum.Light.ActivityChooserView</item>
- <item name="fragmentBreadCrumbsStyle">@style/Widget.Quantum.Light.FragmentBreadCrumbs</item>
<!-- Preference styles -->
<item name="preferenceScreenStyle">@style/Preference.Quantum.PreferenceScreen</item>
diff --git a/core/tests/coretests/src/android/view/VelocityTest.java b/core/tests/coretests/src/android/view/VelocityTest.java
index fb28e1e..12abf3e 100644
--- a/core/tests/coretests/src/android/view/VelocityTest.java
+++ b/core/tests/coretests/src/android/view/VelocityTest.java
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-package com.android.frameworktest.view;
+package android.view;
import junit.framework.Assert;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.MediumTest;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
@@ -30,7 +28,7 @@ import android.view.animation.LinearInterpolator;
/**
* Exercises {@link android.view.VelocityTracker} to compute correct velocity.<br>
* To launch this test, use :<br>
- * <code>./development/testrunner/runtest.py framework -c com.android.frameworktest.view.VelocityTest</code>
+ * <code>./development/testrunner/runtest.py framework -c android.view.VelocityTest</code>
*/
public class VelocityTest extends InstrumentationTestCase {
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index 062acaf..fe53a17 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -272,6 +272,7 @@ public class ImageFormat {
case NV16:
case YUY2:
case YV12:
+ case JPEG:
case NV21:
case YUV_420_888:
case RAW_SENSOR:
diff --git a/graphics/java/android/graphics/LayerRasterizer.java b/graphics/java/android/graphics/LayerRasterizer.java
index 5b35608..e7a24a4 100644
--- a/graphics/java/android/graphics/LayerRasterizer.java
+++ b/graphics/java/android/graphics/LayerRasterizer.java
@@ -16,11 +16,12 @@
package android.graphics;
+@Deprecated
public class LayerRasterizer extends Rasterizer {
public LayerRasterizer() {
native_instance = nativeConstructor();
}
-
+
/** Add a new layer (above any previous layers) to the rasterizer.
The layer will extract those fields that affect the mask from
the specified paint, but will not retain a reference to the paint
diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java
index 66bf75c..b4e6bab 100644
--- a/graphics/java/android/graphics/Matrix.java
+++ b/graphics/java/android/graphics/Matrix.java
@@ -245,6 +245,16 @@ public class Matrix {
}
/**
+ * Gets whether this matrix is affine. An affine matrix preserves
+ * straight lines and has no perspective.
+ *
+ * @return Whether the matrix is affine.
+ */
+ public boolean isAffine() {
+ return native_isAffine(native_instance);
+ }
+
+ /**
* Returns true if will map a rectangle to another rectangle. This can be
* true if the matrix is identity, scale-only, or rotates a multiple of 90
* degrees.
@@ -828,6 +838,7 @@ public class Matrix {
private static native long native_create(long native_src_or_zero);
private static native boolean native_isIdentity(long native_object);
+ private static native boolean native_isAffine(long native_object);
private static native boolean native_rectStaysRect(long native_object);
private static native void native_reset(long native_object);
private static native void native_set(long native_object,
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index b5c0801..c6ba75c 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -53,8 +53,7 @@ public final class Outline {
set(src);
}
- /** @hide */
- public void markInvalid() {
+ public void reset() {
mRadius = 0;
mRect = null;
mPath = null;
@@ -74,27 +73,21 @@ public final class Outline {
*
* @param src Source outline to copy from.
*/
- public void set(@Nullable Outline src) {
- if (src == null) {
- mRadius = 0;
- mRect = null;
- mPath = null;
- } else {
- if (src.mPath != null) {
- if (mPath == null) {
- mPath = new Path();
- }
- mPath.set(src.mPath);
- mRect = null;
+ public void set(@NonNull Outline src) {
+ if (src.mPath != null) {
+ if (mPath == null) {
+ mPath = new Path();
}
- if (src.mRect != null) {
- if (mRect == null) {
- mRect = new Rect();
- }
- mRect.set(src.mRect);
+ mPath.set(src.mPath);
+ mRect = null;
+ }
+ if (src.mRect != null) {
+ if (mRect == null) {
+ mRect = new Rect();
}
- mRadius = src.mRadius;
+ mRect.set(src.mRect);
}
+ mRadius = src.mRadius;
}
/**
@@ -134,6 +127,11 @@ public final class Outline {
* Sets the outline to the oval defined by input rect.
*/
public void setOval(int left, int top, int right, int bottom) {
+ if ((bottom - top) == (right - left)) {
+ // represent circle as round rect, for efficiency, and to enable clipping
+ setRoundRect(left, top, right, bottom, (bottom - top) / 2.0f);
+ return;
+ }
mRect = null;
if (mPath == null) mPath = new Path();
mPath.reset();
@@ -160,4 +158,16 @@ public final class Outline {
mRadius = -1.0f;
mPath.set(convexPath);
}
+
+ /**
+ * Returns whether the outline can be used to clip a View.
+ *
+ * Currently, only outlines that can be represented as a rectangle, circle, or round rect
+ * support clipping.
+ *
+ * @see {@link View#setClipToOutline(boolean)}
+ */
+ public boolean canClip() {
+ return mRect != null;
+ }
}
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index bdef404..92cfd6b 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1064,14 +1064,17 @@ public class Paint {
mNativeTypeface = typefaceNative;
return typeface;
}
-
+
/**
* Get the paint's rasterizer (or null).
* <p />
* The raster controls/modifies how paths/text are turned into alpha masks.
*
* @return the paint's rasterizer (or null)
+ *
+ * @deprecated Rasterizer is not supported by either the HW or PDF backends.
*/
+ @Deprecated
public Rasterizer getRasterizer() {
return mRasterizer;
}
@@ -1085,7 +1088,10 @@ public class Paint {
* @param rasterizer May be null. The new rasterizer to be installed in
* the paint.
* @return rasterizer
+ *
+ * @deprecated Rasterizer is not supported by either the HW or PDF backends.
*/
+ @Deprecated
public Rasterizer setRasterizer(Rasterizer rasterizer) {
long rasterizerNative = 0;
if (rasterizer != null) {
@@ -1095,7 +1101,7 @@ public class Paint {
mRasterizer = rasterizer;
return rasterizer;
}
-
+
/**
* This draws a shadow layer below the main layer, with the specified
* offset and color, and blur radius. If radius is 0, then the shadow
diff --git a/graphics/java/android/graphics/Rasterizer.java b/graphics/java/android/graphics/Rasterizer.java
index 817814c..c351d94e 100644
--- a/graphics/java/android/graphics/Rasterizer.java
+++ b/graphics/java/android/graphics/Rasterizer.java
@@ -21,6 +21,7 @@
package android.graphics;
+@Deprecated
public class Rasterizer {
protected void finalize() throws Throwable {
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 60b4615..6755f3e 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -67,15 +67,22 @@ import java.io.IOException;
* @attr ref android.R.styleable#BitmapDrawable_tileMode
*/
public class BitmapDrawable extends Drawable {
-
private static final int DEFAULT_PAINT_FLAGS =
Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG;
+
+ // Constants for {@link android.R.styleable#BitmapDrawable_tileMode}.
+ private static final int TILE_MODE_UNDEFINED = -2;
+ private static final int TILE_MODE_DISABLED = -1;
+ private static final int TILE_MODE_CLAMP = 0;
+ private static final int TILE_MODE_REPEAT = 1;
+ private static final int TILE_MODE_MIRROR = 2;
+
+ private final Rect mDstRect = new Rect(); // Gravity.apply() sets this
+
private BitmapState mBitmapState;
- private Bitmap mBitmap;
private PorterDuffColorFilter mTintFilter;
- private int mTargetDensity;
- private final Rect mDstRect = new Rect(); // Gravity.apply() sets this
+ private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
private boolean mApplyGravity;
private boolean mMutated;
@@ -100,11 +107,12 @@ public class BitmapDrawable extends Drawable {
/**
* Create an empty drawable, setting initial target density based on
* the display metrics of the resources.
+ *
* @deprecated Use {@link #BitmapDrawable(android.content.res.Resources, android.graphics.Bitmap)}
* instead to specify a bitmap to draw with.
*/
+ @SuppressWarnings("unused")
@Deprecated
- @SuppressWarnings({"UnusedParameters"})
public BitmapDrawable(Resources res) {
mBitmapState = new BitmapState((Bitmap) null);
mBitmapState.mTargetDensity = mTargetDensity;
@@ -137,7 +145,7 @@ public class BitmapDrawable extends Drawable {
@Deprecated
public BitmapDrawable(String filepath) {
this(new BitmapState(BitmapFactory.decodeFile(filepath)), null, null);
- if (mBitmap == null) {
+ if (mBitmapState.mBitmap == null) {
android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
}
}
@@ -145,11 +153,11 @@ public class BitmapDrawable extends Drawable {
/**
* Create a drawable by opening a given file path and decoding the bitmap.
*/
- @SuppressWarnings({"UnusedParameters"})
+ @SuppressWarnings("unused")
public BitmapDrawable(Resources res, String filepath) {
this(new BitmapState(BitmapFactory.decodeFile(filepath)), null, null);
mBitmapState.mTargetDensity = mTargetDensity;
- if (mBitmap == null) {
+ if (mBitmapState.mBitmap == null) {
android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
}
}
@@ -162,7 +170,7 @@ public class BitmapDrawable extends Drawable {
@Deprecated
public BitmapDrawable(java.io.InputStream is) {
this(new BitmapState(BitmapFactory.decodeStream(is)), null, null);
- if (mBitmap == null) {
+ if (mBitmapState.mBitmap == null) {
android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
}
}
@@ -170,11 +178,11 @@ public class BitmapDrawable extends Drawable {
/**
* Create a drawable by decoding a bitmap from the given input stream.
*/
- @SuppressWarnings({"UnusedParameters"})
+ @SuppressWarnings("unused")
public BitmapDrawable(Resources res, java.io.InputStream is) {
this(new BitmapState(BitmapFactory.decodeStream(is)), null, null);
mBitmapState.mTargetDensity = mTargetDensity;
- if (mBitmap == null) {
+ if (mBitmapState.mBitmap == null) {
android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
}
}
@@ -190,22 +198,23 @@ public class BitmapDrawable extends Drawable {
* Returns the bitmap used by this drawable to render. May be null.
*/
public final Bitmap getBitmap() {
- return mBitmap;
+ return mBitmapState.mBitmap;
}
private void computeBitmapSize() {
- mBitmapWidth = mBitmap.getScaledWidth(mTargetDensity);
- mBitmapHeight = mBitmap.getScaledHeight(mTargetDensity);
+ final Bitmap bitmap = mBitmapState.mBitmap;
+ if (bitmap != null) {
+ mBitmapWidth = bitmap.getScaledWidth(mTargetDensity);
+ mBitmapHeight = bitmap.getScaledHeight(mTargetDensity);
+ } else {
+ mBitmapWidth = mBitmapHeight = -1;
+ }
}
private void setBitmap(Bitmap bitmap) {
- if (bitmap != mBitmap) {
- mBitmap = bitmap;
- if (bitmap != null) {
- computeBitmapSize();
- } else {
- mBitmapWidth = mBitmapHeight = -1;
- }
+ if (mBitmapState.mBitmap != bitmap) {
+ mBitmapState.mBitmap = bitmap;
+ computeBitmapSize();
invalidateSelf();
}
}
@@ -247,7 +256,7 @@ public class BitmapDrawable extends Drawable {
public void setTargetDensity(int density) {
if (mTargetDensity != density) {
mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
- if (mBitmap != null) {
+ if (mBitmapState.mBitmap != null) {
computeBitmapSize();
}
invalidateSelf();
@@ -343,8 +352,9 @@ public class BitmapDrawable extends Drawable {
/**
* Indicates the repeat behavior of this drawable on the X axis.
*
- * @return {@link Shader.TileMode#CLAMP} if the bitmap does not repeat,
- * {@link Shader.TileMode#REPEAT} or {@link Shader.TileMode#MIRROR} otherwise.
+ * @return {@link android.graphics.Shader.TileMode#CLAMP} if the bitmap does not repeat,
+ * {@link android.graphics.Shader.TileMode#REPEAT} or
+ * {@link android.graphics.Shader.TileMode#MIRROR} otherwise.
*/
public Shader.TileMode getTileModeX() {
return mBitmapState.mTileModeX;
@@ -353,8 +363,9 @@ public class BitmapDrawable extends Drawable {
/**
* Indicates the repeat behavior of this drawable on the Y axis.
*
- * @return {@link Shader.TileMode#CLAMP} if the bitmap does not repeat,
- * {@link Shader.TileMode#REPEAT} or {@link Shader.TileMode#MIRROR} otherwise.
+ * @return {@link android.graphics.Shader.TileMode#CLAMP} if the bitmap does not repeat,
+ * {@link android.graphics.Shader.TileMode#REPEAT} or
+ * {@link android.graphics.Shader.TileMode#MIRROR} otherwise.
*/
public Shader.TileMode getTileModeY() {
return mBitmapState.mTileModeY;
@@ -362,9 +373,9 @@ public class BitmapDrawable extends Drawable {
/**
* Sets the repeat behavior of this drawable on the X axis. By default, the drawable
- * does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or
- * {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap
- * is smaller than this drawable.
+ * does not repeat its bitmap. Using {@link android.graphics.Shader.TileMode#REPEAT} or
+ * {@link android.graphics.Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled)
+ * if the bitmap is smaller than this drawable.
*
* @param mode The repeat mode for this drawable.
*
@@ -377,9 +388,9 @@ public class BitmapDrawable extends Drawable {
/**
* Sets the repeat behavior of this drawable on the Y axis. By default, the drawable
- * does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or
- * {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap
- * is smaller than this drawable.
+ * does not repeat its bitmap. Using {@link android.graphics.Shader.TileMode#REPEAT} or
+ * {@link android.graphics.Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled)
+ * if the bitmap is smaller than this drawable.
*
* @param mode The repeat mode for this drawable.
*
@@ -392,9 +403,9 @@ public class BitmapDrawable extends Drawable {
/**
* Sets the repeat behavior of this drawable on both axis. By default, the drawable
- * does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or
- * {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap
- * is smaller than this drawable.
+ * does not repeat its bitmap. Using {@link android.graphics.Shader.TileMode#REPEAT} or
+ * {@link android.graphics.Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled)
+ * if the bitmap is smaller than this drawable.
*
* @param xmode The X repeat mode for this drawable.
* @param ymode The Y repeat mode for this drawable.
@@ -462,7 +473,7 @@ public class BitmapDrawable extends Drawable {
@Override
public void draw(Canvas canvas) {
- final Bitmap bitmap = mBitmap;
+ final Bitmap bitmap = mBitmapState.mBitmap;
if (bitmap == null) {
return;
}
@@ -589,7 +600,7 @@ public class BitmapDrawable extends Drawable {
public void setTint(ColorStateList tint) {
if (mBitmapState.mTint != tint) {
mBitmapState.mTint = tint;
- updateTintFilter();
+ computeTintFilter();
invalidateSelf();
}
}
@@ -612,7 +623,7 @@ public class BitmapDrawable extends Drawable {
public void setTintMode(Mode tintMode) {
if (mBitmapState.mTintMode != tintMode) {
mBitmapState.mTintMode = tintMode;
- updateTintFilter();
+ computeTintFilter();
invalidateSelf();
}
}
@@ -624,18 +635,15 @@ public class BitmapDrawable extends Drawable {
return mBitmapState.mTintMode;
}
- /**
- * Ensures the tint filter is consistent with the current tint color and
- * mode.
- */
- private void updateTintFilter() {
- final ColorStateList tint = mBitmapState.mTint;
- final Mode tintMode = mBitmapState.mTintMode;
- if (tint != null && tintMode != null) {
- if (mTintFilter == null) {
- mTintFilter = new PorterDuffColorFilter(0, tintMode);
+ private void computeTintFilter() {
+ final BitmapState state = mBitmapState;
+ if (state.mTint != null && state.mTintMode != null) {
+ final int color = state.mTint.getColorForState(getState(), 0);
+ if (mTintFilter != null) {
+ mTintFilter.setColor(color);
+ mTintFilter.setMode(state.mTintMode);
} else {
- mTintFilter.setMode(tintMode);
+ mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
}
} else {
mTintFilter = null;
@@ -693,16 +701,15 @@ public class BitmapDrawable extends Drawable {
throws XmlPullParserException, IOException {
super.inflate(r, parser, attrs, theme);
- final TypedArray a = obtainAttributes(
- r, theme, attrs, R.styleable.BitmapDrawable);
- inflateStateFromTypedArray(a);
+ final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.BitmapDrawable);
+ updateStateFromTypedArray(a);
a.recycle();
}
/**
- * Initializes the constant state from the values in the typed array.
+ * Updates the constant state from the values in the typed array.
*/
- private void inflateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
+ private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
final Resources r = a.getResources();
final BitmapState state = mBitmapState;
@@ -710,86 +717,52 @@ public class BitmapDrawable extends Drawable {
final int[] themeAttrs = a.extractThemeAttrs();
state.mThemeAttrs = themeAttrs;
- if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_src] == 0) {
- final int id = a.getResourceId(R.styleable.BitmapDrawable_src, 0);
- if (id == 0) {
- throw new XmlPullParserException(a.getPositionDescription() +
- ": <bitmap> requires a valid src attribute");
- }
-
- final Bitmap bitmap = BitmapFactory.decodeResource(r, id);
+ final int srcResId = a.getResourceId(R.styleable.BitmapDrawable_src, 0);
+ if (srcResId != 0) {
+ final Bitmap bitmap = BitmapFactory.decodeResource(r, srcResId);
if (bitmap == null) {
throw new XmlPullParserException(a.getPositionDescription() +
": <bitmap> requires a valid src attribute");
}
+
state.mBitmap = bitmap;
- setBitmap(bitmap);
}
- setTargetDensity(r.getDisplayMetrics());
+ state.mTargetDensity = r.getDisplayMetrics().densityDpi;
- if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_mipMap] == 0) {
- final boolean defMipMap = state.mBitmap != null ? state.mBitmap.hasMipMap() : false;
- final boolean mipMap = a.getBoolean(
- R.styleable.BitmapDrawable_mipMap, defMipMap);
- setMipMap(mipMap);
- }
+ final boolean defMipMap = state.mBitmap != null ? state.mBitmap.hasMipMap() : false;
+ setMipMap(a.getBoolean(R.styleable.BitmapDrawable_mipMap, defMipMap));
- if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_autoMirrored] == 0) {
- final boolean autoMirrored = a.getBoolean(
- R.styleable.BitmapDrawable_autoMirrored, false);
- setAutoMirrored(autoMirrored);
- }
+ state.mAutoMirrored = a.getBoolean(
+ R.styleable.BitmapDrawable_autoMirrored, state.mAutoMirrored);
+ state.mBaseAlpha = a.getFloat(R.styleable.BitmapDrawable_alpha, state.mBaseAlpha);
- if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_tintMode] == 0) {
- final int tintModeValue = a.getInt(
- R.styleable.BitmapDrawable_tintMode, -1);
- state.mTintMode = Drawable.parseTintMode(tintModeValue, Mode.SRC_IN);
+ final int tintMode = a.getInt(R.styleable.BitmapDrawable_tintMode, -1);
+ if (tintMode != -1) {
+ state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
}
- if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_tint] == 0) {
- state.mTint = a.getColorStateList(R.styleable.BitmapDrawable_tint);
- if (state.mTint != null) {
- final int color = state.mTint.getColorForState(getState(), 0);
- mTintFilter = new PorterDuffColorFilter(color, mBitmapState.mTintMode);
- }
+ final ColorStateList tint = a.getColorStateList(R.styleable.BitmapDrawable_tint);
+ if (tint != null) {
+ state.mTint = tint;
}
final Paint paint = mBitmapState.mPaint;
+ paint.setAntiAlias(a.getBoolean(
+ R.styleable.BitmapDrawable_antialias, paint.isAntiAlias()));
+ paint.setFilterBitmap(a.getBoolean(
+ R.styleable.BitmapDrawable_filter, paint.isFilterBitmap()));
+ paint.setDither(a.getBoolean(R.styleable.BitmapDrawable_dither, paint.isDither()));
- if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_antialias] == 0) {
- final boolean antiAlias = a.getBoolean(
- R.styleable.BitmapDrawable_antialias, paint.isAntiAlias());
- paint.setAntiAlias(antiAlias);
- }
-
- if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_filter] == 0) {
- final boolean filter = a.getBoolean(
- R.styleable.BitmapDrawable_filter, paint.isFilterBitmap());
- paint.setFilterBitmap(filter);
- }
+ setGravity(a.getInt(R.styleable.BitmapDrawable_gravity, state.mGravity));
- if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_dither] == 0) {
- final boolean dither = a.getBoolean(
- R.styleable.BitmapDrawable_dither, paint.isDither());
- paint.setDither(dither);
- }
-
- if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_alpha] == 0) {
- state.mBaseAlpha = a.getFloat(R.styleable.BitmapDrawable_alpha, 1.0f);
- }
-
- if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_gravity] == 0) {
- final int gravity = a.getInt(
- R.styleable.BitmapDrawable_gravity, Gravity.FILL);
- setGravity(gravity);
- }
-
- if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_tileMode] == 0) {
- final int tileMode = a.getInt(
- R.styleable.BitmapDrawable_tileMode, -1);
+ final int tileMode = a.getInt(R.styleable.BitmapDrawable_tileMode, TILE_MODE_UNDEFINED);
+ if (tileMode != TILE_MODE_UNDEFINED) {
setTileModeInternal(tileMode);
}
+
+ // Update local properties.
+ initializeWithState(state, r);
}
@Override
@@ -797,120 +770,32 @@ public class BitmapDrawable extends Drawable {
super.applyTheme(t);
final BitmapState state = mBitmapState;
- if (state == null) {
- throw new RuntimeException("Can't apply theme to <bitmap> with no constant state");
+ if (state == null || state.mThemeAttrs == null) {
+ return;
}
- final int[] themeAttrs = state.mThemeAttrs;
- if (themeAttrs != null) {
- final TypedArray a = t.resolveAttributes(themeAttrs, R.styleable.BitmapDrawable, 0, 0);
+ final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.BitmapDrawable);
+ try {
updateStateFromTypedArray(a);
+ } catch (XmlPullParserException e) {
+ throw new RuntimeException(e);
+ } finally {
a.recycle();
}
}
- /**
- * Updates the constant state from the values in the typed array.
- */
- private void updateStateFromTypedArray(TypedArray a) {
- final Resources r = a.getResources();
- final BitmapState state = mBitmapState;
- final Paint paint = mBitmapState.mPaint;
-
- if (a.hasValue(R.styleable.BitmapDrawable_antialias)) {
- final boolean antiAlias = a.getBoolean(
- R.styleable.BitmapDrawable_antialias, paint.isAntiAlias());
- paint.setAntiAlias(antiAlias);
- }
-
- if (a.hasValue(R.styleable.BitmapDrawable_filter)) {
- final boolean filter = a.getBoolean(
- R.styleable.BitmapDrawable_filter, paint.isFilterBitmap());
- paint.setFilterBitmap(filter);
- }
-
- if (a.hasValue(R.styleable.BitmapDrawable_dither)) {
- final boolean dither = a.getBoolean(
- R.styleable.BitmapDrawable_dither, paint.isDither());
- paint.setDither(dither);
- }
-
- if (a.hasValue(R.styleable.BitmapDrawable_alpha)) {
- state.mBaseAlpha = a.getFloat(R.styleable.BitmapDrawable_alpha, state.mBaseAlpha);
- }
-
- if (a.hasValue(R.styleable.BitmapDrawable_gravity)) {
- final int gravity = a.getInt(
- R.styleable.BitmapDrawable_gravity, Gravity.FILL);
- setGravity(gravity);
- }
-
- if (a.hasValue(R.styleable.BitmapDrawable_tileMode)) {
- final int tileMode = a.getInt(
- R.styleable.BitmapDrawable_tileMode, -1);
- setTileModeInternal(tileMode);
- }
-
- if (a.hasValue(R.styleable.BitmapDrawable_src)) {
- final int id = a.getResourceId(R.styleable.BitmapDrawable_src, 0);
- if (id == 0) {
- throw new RuntimeException(a.getPositionDescription() +
- ": <bitmap> requires a valid src attribute");
- }
-
- final Bitmap bitmap = BitmapFactory.decodeResource(r, id);
- if (bitmap == null) {
- throw new RuntimeException(a.getPositionDescription() +
- ": <bitmap> requires a valid src attribute");
- }
-
- setBitmap(bitmap);
- }
-
- setTargetDensity(r.getDisplayMetrics());
-
- if (a.hasValue(R.styleable.BitmapDrawable_mipMap)) {
- final boolean mipMap = a.getBoolean(
- R.styleable.BitmapDrawable_mipMap,
- state.mBitmap.hasMipMap());
- setMipMap(mipMap);
- }
-
- if (a.hasValue(R.styleable.BitmapDrawable_autoMirrored)) {
- final boolean autoMirrored = a.getBoolean(
- R.styleable.BitmapDrawable_autoMirrored, false);
- setAutoMirrored(autoMirrored);
- }
-
- if (a.hasValue(R.styleable.BitmapDrawable_tintMode)) {
- final int modeValue = a.getInt(
- R.styleable.BitmapDrawable_tintMode, -1);
- state.mTintMode = Drawable.parseTintMode(modeValue, Mode.SRC_IN);
- }
-
- if (a.hasValue(R.styleable.BitmapDrawable_tint)) {
- final ColorStateList tint = a.getColorStateList(
- R.styleable.BitmapDrawable_tint);
- if (tint != null) {
- state.mTint = tint;
- final int color = tint.getColorForState(getState(), 0);
- mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
- }
- }
- }
-
private void setTileModeInternal(final int tileMode) {
switch (tileMode) {
- case -1:
- // Do nothing.
+ case TILE_MODE_DISABLED:
+ setTileModeXY(null, null);
break;
- case 0:
+ case TILE_MODE_CLAMP:
setTileModeXY(Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
break;
- case 1:
+ case TILE_MODE_REPEAT:
setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
break;
- case 2:
+ case TILE_MODE_MIRROR:
setTileModeXY(Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
break;
}
@@ -936,8 +821,9 @@ public class BitmapDrawable extends Drawable {
if (mBitmapState.mGravity != Gravity.FILL) {
return PixelFormat.TRANSLUCENT;
}
- Bitmap bm = mBitmap;
- return (bm == null || bm.hasAlpha() || mBitmapState.mPaint.getAlpha() < 255) ?
+
+ final Bitmap bitmap = mBitmapState.mBitmap;
+ return (bitmap == null || bitmap.hasAlpha() || mBitmapState.mPaint.getAlpha() < 255) ?
PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
}
@@ -948,22 +834,26 @@ public class BitmapDrawable extends Drawable {
}
final static class BitmapState extends ConstantState {
- Bitmap mBitmap;
- ColorStateList mTint;
+ final Paint mPaint;
+
+ // Values loaded during inflation.
+ int[] mThemeAttrs = null;
+ Bitmap mBitmap = null;
+ ColorStateList mTint = null;
Mode mTintMode = Mode.SRC_IN;
- int[] mThemeAttrs;
- int mChangingConfigurations;
int mGravity = Gravity.FILL;
float mBaseAlpha = 1.0f;
- Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS);
Shader.TileMode mTileModeX = null;
Shader.TileMode mTileModeY = null;
int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
+ boolean mAutoMirrored = false;
+
+ int mChangingConfigurations;
boolean mRebuildShader;
- boolean mAutoMirrored;
BitmapState(Bitmap bitmap) {
mBitmap = bitmap;
+ mPaint = new Paint(DEFAULT_PAINT_FLAGS);
}
BitmapState(BitmapState bitmapState) {
@@ -1013,6 +903,10 @@ public class BitmapDrawable extends Drawable {
}
}
+ /**
+ * The one constructor to rule them all. This is called by all public
+ * constructors to set the state and initialize local properties.
+ */
private BitmapDrawable(BitmapState state, Resources res, Theme theme) {
if (theme != null && state.canApplyTheme()) {
mBitmapState = new BitmapState(state);
@@ -1034,11 +928,7 @@ public class BitmapDrawable extends Drawable {
mTargetDensity = state.mTargetDensity;
}
- if (state.mTint != null) {
- final int color = state.mTint.getColorForState(getState(), 0);
- mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
- }
-
- setBitmap(state.mBitmap);
+ computeTintFilter();
+ computeBitmapSize();
}
}
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 8243b7c..df5ca33 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -199,7 +199,7 @@ public class ColorDrawable extends Drawable {
final int[] themeAttrs = state.mThemeAttrs;
if (themeAttrs != null) {
- final TypedArray a = t.resolveAttributes(themeAttrs, R.styleable.ColorDrawable, 0, 0);
+ final TypedArray a = t.resolveAttributes(themeAttrs, R.styleable.ColorDrawable);
updateStateFromTypedArray(a);
a.recycle();
}
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index dc06350..8fe1544 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -1053,7 +1053,7 @@ public class GradientDrawable extends Drawable {
final int[] themeAttrs = state.mThemeAttrs;
if (themeAttrs != null) {
final TypedArray a = t.resolveAttributes(
- themeAttrs, R.styleable.GradientDrawable, 0, 0);
+ themeAttrs, R.styleable.GradientDrawable);
updateStateFromTypedArray(a);
a.recycle();
@@ -1123,37 +1123,37 @@ public class GradientDrawable extends Drawable {
TypedArray a;
if (state.mAttrSize != null) {
- a = t.resolveAttributes(state.mAttrSize, R.styleable.GradientDrawableSize, 0, 0);
+ a = t.resolveAttributes(state.mAttrSize, R.styleable.GradientDrawableSize);
// TODO: updateGradientDrawableSize(a);
a.recycle();
}
if (state.mAttrGradient != null) {
- a = t.resolveAttributes(state.mAttrGradient, R.styleable.GradientDrawableGradient, 0, 0);
+ a = t.resolveAttributes(state.mAttrGradient, R.styleable.GradientDrawableGradient);
// TODO: updateGradientDrawableGradient(a);
a.recycle();
}
if (state.mAttrSolid != null) {
- a = t.resolveAttributes(state.mAttrSolid, R.styleable.GradientDrawableSolid, 0, 0);
+ a = t.resolveAttributes(state.mAttrSolid, R.styleable.GradientDrawableSolid);
// TODO: updateGradientDrawableSolid(a);
a.recycle();
}
if (state.mAttrStroke != null) {
- a = t.resolveAttributes(state.mAttrStroke, R.styleable.GradientDrawableStroke, 0, 0);
+ a = t.resolveAttributes(state.mAttrStroke, R.styleable.GradientDrawableStroke);
// TODO: updateGradientDrawableStroke(a);
a.recycle();
}
if (state.mAttrCorners != null) {
- a = t.resolveAttributes(state.mAttrCorners, R.styleable.DrawableCorners, 0, 0);
+ a = t.resolveAttributes(state.mAttrCorners, R.styleable.DrawableCorners);
// TODO: updateDrawableCorners(a);
a.recycle();
}
if (state.mAttrPadding != null) {
- a = t.resolveAttributes(state.mAttrPadding, R.styleable.GradientDrawablePadding, 0, 0);
+ a = t.resolveAttributes(state.mAttrPadding, R.styleable.GradientDrawablePadding);
// TODO: updateGradientDrawablePadding(a);
a.recycle();
}
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 639d719..7847aad 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -229,7 +229,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
final int[] themeAttrs = state.mThemeAttrs;
if (themeAttrs != null) {
- final TypedArray a = t.resolveAttributes(themeAttrs, R.styleable.LayerDrawable, 0, 0);
+ final TypedArray a = t.resolveAttributes(themeAttrs, R.styleable.LayerDrawable);
updateStateFromTypedArray(a);
a.recycle();
}
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 21992ce..3e09707 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -72,8 +72,8 @@ public class NinePatchDrawable extends Drawable {
private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
// These are scaled to match the target density.
- private int mBitmapWidth;
- private int mBitmapHeight;
+ private int mBitmapWidth = -1;
+ private int mBitmapHeight = -1;
NinePatchDrawable() {
mNinePatchState = new NinePatchState();
@@ -209,7 +209,7 @@ public class NinePatchDrawable extends Drawable {
}
private void setNinePatch(NinePatch ninePatch) {
- if (ninePatch != mNinePatch) {
+ if (mNinePatch != ninePatch) {
mNinePatch = ninePatch;
if (ninePatch != null) {
computeBitmapSize();
@@ -339,7 +339,7 @@ public class NinePatchDrawable extends Drawable {
public void setTint(ColorStateList tint) {
if (mNinePatchState.mTint != tint) {
mNinePatchState.mTint = tint;
- updateTintFilter();
+ computeTintFilter();
invalidateSelf();
}
}
@@ -362,23 +362,20 @@ public class NinePatchDrawable extends Drawable {
public void setTintMode(Mode tintMode) {
if (mNinePatchState.mTintMode != tintMode) {
mNinePatchState.mTintMode = tintMode;
- updateTintFilter();
+ computeTintFilter();
invalidateSelf();
}
}
- /**
- * Ensures the tint filter is consistent with the current tint color and
- * mode.
- */
- private void updateTintFilter() {
- final ColorStateList tint = mNinePatchState.mTint;
- final Mode tintMode = mNinePatchState.mTintMode;
- if (tint != null && tintMode != null) {
- if (mTintFilter == null) {
- mTintFilter = new PorterDuffColorFilter(0, tintMode);
+ private void computeTintFilter() {
+ final NinePatchState state = mNinePatchState;
+ if (state.mTint != null && state.mTintMode != null) {
+ final int color = state.mTint.getColorForState(getState(), 0);
+ if (mTintFilter != null) {
+ mTintFilter.setColor(color);
+ mTintFilter.setMode(state.mTintMode);
} else {
- mTintFilter.setMode(tintMode);
+ mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
}
} else {
mTintFilter = null;
@@ -422,38 +419,28 @@ public class NinePatchDrawable extends Drawable {
throws XmlPullParserException, IOException {
super.inflate(r, parser, attrs, theme);
- final TypedArray a = obtainAttributes(
- r, theme, attrs, R.styleable.NinePatchDrawable);
- inflateStateFromTypedArray(a);
+ final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.NinePatchDrawable);
+ updateStateFromTypedArray(a);
a.recycle();
}
/**
- * Initializes the constant state from the values in the typed array.
+ * Updates the constant state from the values in the typed array.
*/
- private void inflateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
+ private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
final Resources r = a.getResources();
- final NinePatchState ninePatchState = mNinePatchState;
+ final NinePatchState state = mNinePatchState;
// Extract the theme attributes, if any.
final int[] themeAttrs = a.extractThemeAttrs();
- ninePatchState.mThemeAttrs = themeAttrs;
+ state.mThemeAttrs = themeAttrs;
- if (themeAttrs == null || themeAttrs[R.styleable.NinePatchDrawable_dither] == 0) {
- final boolean dither = a.getBoolean(
- R.styleable.NinePatchDrawable_dither, DEFAULT_DITHER);
- ninePatchState.mDither = dither;
- }
-
- if (themeAttrs == null || themeAttrs[R.styleable.NinePatchDrawable_src] == 0) {
- final int id = a.getResourceId(R.styleable.NinePatchDrawable_src, 0);
- if (id == 0) {
- throw new XmlPullParserException(a.getPositionDescription() +
- ": <nine-patch> requires a valid src attribute");
- }
+ state.mDither = a.getBoolean(R.styleable.NinePatchDrawable_dither, state.mDither);
+ final int srcResId = a.getResourceId(R.styleable.NinePatchDrawable_src, 0);
+ if (srcResId != 0) {
final BitmapFactory.Options options = new BitmapFactory.Options();
- options.inDither = !ninePatchState.mDither;
+ options.inDither = !state.mDither;
options.inScreenDensity = r.getDisplayMetrics().noncompatDensityDpi;
final Rect padding = new Rect();
@@ -462,7 +449,7 @@ public class NinePatchDrawable extends Drawable {
try {
final TypedValue value = new TypedValue();
- final InputStream is = r.openRawResource(id, value);
+ final InputStream is = r.openRawResource(srcResId, value);
bitmap = BitmapFactory.decodeResourceStream(r, value, is, padding, options);
@@ -479,40 +466,30 @@ public class NinePatchDrawable extends Drawable {
": <nine-patch> requires a valid 9-patch source image");
}
- final NinePatch ninePatch = new NinePatch(bitmap, bitmap.getNinePatchChunk());
- ninePatchState.mNinePatch = ninePatch;
- ninePatchState.mPadding = padding;
- ninePatchState.mOpticalInsets = Insets.of(opticalInsets);
- }
-
- if (themeAttrs == null || themeAttrs[R.styleable.NinePatchDrawable_autoMirrored] == 0) {
- final boolean autoMirrored = a.getBoolean(
- R.styleable.NinePatchDrawable_autoMirrored, false);
- ninePatchState.mAutoMirrored = autoMirrored;
+ state.mNinePatch = new NinePatch(bitmap, bitmap.getNinePatchChunk());
+ state.mPadding = padding;
+ state.mOpticalInsets = Insets.of(opticalInsets);
}
- if (themeAttrs == null || themeAttrs[R.styleable.NinePatchDrawable_tintMode] == 0) {
- final int tintModeValue = a.getInt(R.styleable.NinePatchDrawable_tintMode, -1);
- ninePatchState.mTintMode = Drawable.parseTintMode(tintModeValue, Mode.SRC_IN);
- }
+ state.mAutoMirrored = a.getBoolean(
+ R.styleable.NinePatchDrawable_autoMirrored, state.mAutoMirrored);
+ state.mBaseAlpha = a.getFloat(R.styleable.NinePatchDrawable_alpha, state.mBaseAlpha);
- if (themeAttrs == null || themeAttrs[R.styleable.NinePatchDrawable_tint] == 0) {
- ninePatchState.mTint = a.getColorStateList(R.styleable.NinePatchDrawable_tint);
- if (ninePatchState.mTint != null) {
- final int color = ninePatchState.mTint.getColorForState(getState(), 0);
- mTintFilter = new PorterDuffColorFilter(color, ninePatchState.mTintMode);
- }
+ final int tintMode = a.getInt(R.styleable.NinePatchDrawable_tintMode, -1);
+ if (tintMode != -1) {
+ state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
}
- if (themeAttrs == null || themeAttrs[R.styleable.NinePatchDrawable_alpha] == 0) {
- ninePatchState.mBaseAlpha = a.getFloat(R.styleable.NinePatchDrawable_alpha, 1.0f);
+ final ColorStateList tint = a.getColorStateList(R.styleable.NinePatchDrawable_tint);
+ if (tint != null) {
+ state.mTint = tint;
}
- // Apply the constant state to the paint.
- initializeWithState(ninePatchState, r);
+ // Update local properties.
+ initializeWithState(state, r);
// Push density applied by setNinePatchState into state.
- ninePatchState.mTargetDensity = mTargetDensity;
+ state.mTargetDensity = mTargetDensity;
}
@Override
@@ -520,98 +497,20 @@ public class NinePatchDrawable extends Drawable {
super.applyTheme(t);
final NinePatchState state = mNinePatchState;
- if (state == null) {
- throw new RuntimeException("Can't apply theme to <nine-patch> with no constant state");
+ if (state == null || state.mThemeAttrs == null) {
+ return;
}
- final int[] themeAttrs = state.mThemeAttrs;
- if (themeAttrs != null) {
- final TypedArray a = t.resolveAttributes(
- themeAttrs, R.styleable.NinePatchDrawable, 0, 0);
+ final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.NinePatchDrawable);
+ try {
updateStateFromTypedArray(a);
+ } catch (XmlPullParserException e) {
+ throw new RuntimeException(e);
+ } finally {
a.recycle();
}
}
- /**
- * Updates the constant state from the values in the typed array.
- */
- private void updateStateFromTypedArray(TypedArray a) {
- final Resources r = a.getResources();
- final NinePatchState state = mNinePatchState;
-
- if (a.hasValue(R.styleable.NinePatchDrawable_dither)) {
- state.mDither = a.getBoolean(R.styleable.NinePatchDrawable_dither, DEFAULT_DITHER);
- }
-
- if (a.hasValue(R.styleable.NinePatchDrawable_autoMirrored)) {
- state.mAutoMirrored = a.getBoolean(R.styleable.NinePatchDrawable_autoMirrored, false);
- }
-
- if (a.hasValue(R.styleable.NinePatchDrawable_src)) {
- final int id = a.getResourceId(R.styleable.NinePatchDrawable_src, 0);
- if (id == 0) {
- throw new RuntimeException(a.getPositionDescription() +
- ": <nine-patch> requires a valid src attribute");
- }
-
- final BitmapFactory.Options options = new BitmapFactory.Options();
- options.inDither = !state.mDither;
- options.inScreenDensity = r.getDisplayMetrics().noncompatDensityDpi;
-
- final Rect padding = new Rect();
- final Rect opticalInsets = new Rect();
- Bitmap bitmap = null;
-
- try {
- final TypedValue value = new TypedValue();
- final InputStream is = r.openRawResource(id, value);
-
- bitmap = BitmapFactory.decodeResourceStream(r, value, is, padding, options);
-
- is.close();
- } catch (IOException e) {
- // Ignore
- }
-
- if (bitmap == null) {
- throw new RuntimeException(a.getPositionDescription() +
- ": <nine-patch> requires a valid src attribute");
- } else if (bitmap.getNinePatchChunk() == null) {
- throw new RuntimeException(a.getPositionDescription() +
- ": <nine-patch> requires a valid 9-patch source image");
- }
-
- state.mNinePatch = new NinePatch(bitmap, bitmap.getNinePatchChunk());
- state.mPadding = padding;
- state.mOpticalInsets = Insets.of(opticalInsets);
- }
-
- if (a.hasValue(R.styleable.NinePatchDrawable_tintMode)) {
- final int modeValue = a.getInt(R.styleable.NinePatchDrawable_tintMode, -1);
- state.mTintMode = Drawable.parseTintMode(modeValue, Mode.SRC_IN);
- }
-
- if (a.hasValue(R.styleable.NinePatchDrawable_tint)) {
- final ColorStateList tint = a.getColorStateList(R.styleable.NinePatchDrawable_tint);
- if (tint != null) {
- state.mTint = tint;
- final int color = tint.getColorForState(getState(), 0);
- mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
- }
- }
-
- if (a.hasValue(R.styleable.NinePatchDrawable_alpha)) {
- state.mBaseAlpha = a.getFloat(R.styleable.NinePatchDrawable_alpha, 1.0f);
- }
-
- // Apply the constant state to the paint.
- initializeWithState(state, r);
-
- // Push density applied by setNinePatchState into state.
- state.mTargetDensity = mTargetDensity;
- }
-
@Override
public boolean canApplyTheme() {
return mNinePatchState != null && mNinePatchState.mThemeAttrs != null;
@@ -705,17 +604,19 @@ public class NinePatchDrawable extends Drawable {
}
final static class NinePatchState extends ConstantState {
- NinePatch mNinePatch;
- ColorStateList mTint;
+ // Values loaded during inflation.
+ int[] mThemeAttrs = null;
+ NinePatch mNinePatch = null;
+ ColorStateList mTint = null;
Mode mTintMode = Mode.SRC_IN;
- Rect mPadding;
- Insets mOpticalInsets;
+ Rect mPadding = null;
+ Insets mOpticalInsets = Insets.NONE;
float mBaseAlpha = 1.0f;
- boolean mDither;
- int[] mThemeAttrs;
- int mChangingConfigurations;
+ boolean mDither = DEFAULT_DITHER;
int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
- boolean mAutoMirrored;
+ boolean mAutoMirrored = false;
+
+ int mChangingConfigurations;
NinePatchState() {
// Empty constructor.
@@ -786,6 +687,10 @@ public class NinePatchDrawable extends Drawable {
}
}
+ /**
+ * The one constructor to rule them all. This is called by all public
+ * constructors to set the state and initialize local properties.
+ */
private NinePatchDrawable(NinePatchState state, Resources res, Theme theme) {
if (theme != null && state.canApplyTheme()) {
mNinePatchState = new NinePatchState(state);
@@ -812,14 +717,12 @@ public class NinePatchDrawable extends Drawable {
setDither(state.mDither);
}
- if (state.mTint != null) {
- final int color = state.mTint.getColorForState(getState(), 0);
- mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
+ // Make a local copy of the padding.
+ if (state.mPadding != null) {
+ mPadding = new Rect(state.mPadding);
}
- final Rect statePadding = state.mPadding;
- mPadding = statePadding != null ? new Rect(statePadding) : null;
-
+ computeTintFilter();
setNinePatch(state.mNinePatch);
}
}
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index 0097183..8128b5f 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -291,7 +291,7 @@ public class TouchFeedbackDrawable extends LayerDrawable {
final int[] themeAttrs = state.mTouchThemeAttrs;
if (themeAttrs != null) {
final TypedArray a = t.resolveAttributes(
- themeAttrs, R.styleable.TouchFeedbackDrawable, 0, 0);
+ themeAttrs, R.styleable.TouchFeedbackDrawable);
updateStateFromTypedArray(a);
a.recycle();
}
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 2da8615..05658f5 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -753,7 +753,7 @@ public class VectorDrawable extends Drawable {
}
final TypedArray a = t.resolveAttributes(
- mThemeAttrs, R.styleable.VectorDrawablePath, 0, 0);
+ mThemeAttrs, R.styleable.VectorDrawablePath);
mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
diff --git a/graphics/java/android/graphics/pdf/PdfDocument.java b/graphics/java/android/graphics/pdf/PdfDocument.java
index f5b07c1..d603436 100644
--- a/graphics/java/android/graphics/pdf/PdfDocument.java
+++ b/graphics/java/android/graphics/pdf/PdfDocument.java
@@ -32,7 +32,7 @@ import java.util.List;
/**
* <p>
* This class enables generating a PDF document from native Android content. You
- * open a new document and then for every page you want to add you start a page,
+ * create a new document and then for every page you want to add you start a page,
* write content to the page, and finish the page. After you are done with all
* pages, you write the document to an output stream and close the document.
* After a document is closed you should not use it anymore. Note that pages are
@@ -64,7 +64,7 @@ import java.util.List;
* // write the document content
* document.writeTo(getOutputStream());
*
- * //close the document
+ * // close the document
* document.close();
* </pre>
*/
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
new file mode 100644
index 0000000..3fa3b9f
--- /dev/null
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -0,0 +1,391 @@
+/*
+ * 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.graphics.pdf;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.OsConstants;
+import dalvik.system.CloseGuard;
+import libcore.io.Libcore;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * <p>
+ * This class enables rendering a PDF document. This class is not thread safe.
+ * </p>
+ * <p>
+ * If you want to render a PDF, you create a renderer and for every page you want
+ * to render, you open the page, render it, and close the page. After you are done
+ * with rendering, you close the renderer. After the renderer is closed it should not
+ * be used anymore. Note that the pages are rendered one by one, i.e. you can have
+ * only a single page opened at any given time.
+ * </p>
+ * <p>
+ * A typical use of the APIs to render a PDF looks like this:
+ * </p>
+ * <pre>
+ * // create a new renderer
+ * PdfRenderer renderer = new PdfRenderer(getSeekableFileDescriptor());
+ *
+ * // let us just render all pages
+ * final int pageCount = renderer.getPageCount();
+ * for (int i = 0; i < pageCount; i++) {
+ * Page page = renderer.openPage(i);
+ * Bitmap bitmap = getBitmapReuseIfPossible(page);
+ *
+ * // say we render for showing on the screen
+ * page.render(bitmap, getContentBoundsInBitmap(),
+ * getDesiredTransformation(), Page.RENDER_MODE_FOR_DISPLAY);
+ *
+ * // do stuff with the bitmap
+ *
+ * renderer.closePage(page);
+ * }
+ *
+ * // close the renderer
+ * renderer.close();
+ * </pre>
+ *
+ * @see #close()
+ */
+public final class PdfRenderer implements AutoCloseable {
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ private final Point mTempPoint = new Point();
+
+ private final long mNativeDocument;
+
+ private final int mPageCount;
+
+ private ParcelFileDescriptor mInput;
+
+ private Page mCurrentPage;
+
+ /** @hide */
+ @IntDef({
+ Page.RENDER_MODE_FOR_DISPLAY,
+ Page.RENDER_MODE_FOR_PRINT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RenderMode {}
+
+ /**
+ * Creates a new instance.
+ * <p>
+ * <strong>Note:</strong> The provided file descriptor must be <strong>seekable</strong>,
+ * i.e. its data being randomly accessed, e.g. pointing to a file.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> This class takes ownership of the passed in file descriptor
+ * and is responsible for closing it when the renderer is closed.
+ * </p>
+ *
+ * @param input Seekable file descriptor to read from.
+ */
+ public PdfRenderer(@NonNull ParcelFileDescriptor input) throws IOException {
+ if (input == null) {
+ throw new NullPointerException("input cannot be null");
+ }
+
+ final long size;
+ try {
+ Libcore.os.lseek(input.getFileDescriptor(), 0, OsConstants.SEEK_SET);
+ size = Libcore.os.fstat(input.getFileDescriptor()).st_size;
+ } catch (ErrnoException ee) {
+ throw new IllegalArgumentException("file descriptor not seekable");
+ }
+
+ mInput = input;
+ mNativeDocument = nativeCreate(mInput.getFd(), size);
+ mPageCount = nativeGetPageCount(mNativeDocument);
+ mCloseGuard.open("close");
+ }
+
+ /**
+ * Closes this renderer. You should not use this instance
+ * after this method is called.
+ */
+ public void close() {
+ throwIfClosed();
+ throwIfPageOpened();
+ doClose();
+ }
+
+ /**
+ * Gets the number of pages in the document.
+ *
+ * @return The page count.
+ */
+ public int getPageCount() {
+ throwIfClosed();
+ return mPageCount;
+ }
+
+ /**
+ * Gets whether the document prefers to be scaled for printing.
+ * You should take this info account if the document is rendered
+ * for printing and the target media size differs from the page
+ * size.
+ *
+ * @return If to scale the document.
+ */
+ public boolean shouldScaleForPrinting() {
+ throwIfClosed();
+ return nativeScaleForPrinting(mNativeDocument);
+ }
+
+ /**
+ * Opens a page for rendering.
+ *
+ * @param index The page index.
+ * @return A page that can be rendered.
+ *
+ * @see #closePage(PdfRenderer.Page)
+ */
+ public Page openPage(int index) {
+ throwIfClosed();
+ throwIfPageOpened();
+ mCurrentPage = new Page(index);
+ return mCurrentPage;
+ }
+
+ /**
+ * Closes a page opened for rendering.
+ *
+ * @param page The page to close.
+ *
+ * @see #openPage(int)
+ */
+ public void closePage(@NonNull Page page) {
+ throwIfClosed();
+ throwIfNotCurrentPage(page);
+ throwIfCurrentPageClosed();
+ mCurrentPage.close();
+ mCurrentPage = null;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ mCloseGuard.warnIfOpen();
+ if (mInput != null) {
+ doClose();
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private void doClose() {
+ if (mCurrentPage != null) {
+ mCurrentPage.close();
+ mCurrentPage = null;
+ }
+ nativeClose(mNativeDocument);
+ try {
+ mInput.close();
+ } catch (IOException ioe) {
+ /* ignore - best effort */
+ }
+ mInput = null;
+ mCloseGuard.close();
+ }
+
+ private void throwIfClosed() {
+ if (mInput == null) {
+ throw new IllegalStateException("Already closed");
+ }
+ }
+
+ private void throwIfPageOpened() {
+ if (mCurrentPage != null) {
+ throw new IllegalStateException("Current page not closed");
+ }
+ }
+
+ private void throwIfCurrentPageClosed() {
+ if (mCurrentPage == null) {
+ throw new IllegalStateException("Already closed");
+ }
+ }
+
+ private void throwIfNotCurrentPage(Page page) {
+ if (page != mCurrentPage) {
+ throw new IllegalArgumentException("Page not from document");
+ }
+ }
+
+ /**
+ * This class represents a PDF document page for rendering.
+ */
+ public final class Page {
+
+ /**
+ * Mode to render the content for display on a screen.
+ */
+ public static final int RENDER_MODE_FOR_DISPLAY = 1;
+
+ /**
+ * Mode to render the content for printing.
+ */
+ public static final int RENDER_MODE_FOR_PRINT = 2;
+
+ private final int mIndex;
+ private final int mWidth;
+ private final int mHeight;
+
+ private long mNativePage;
+
+ private Page(int index) {
+ Point size = mTempPoint;
+ mNativePage = nativeOpenPageAndGetSize(mNativeDocument, index, size);
+ mIndex = index;
+ mWidth = size.x;
+ mHeight = size.y;
+ }
+
+ /**
+ * Gets the page index.
+ *
+ * @return The index.
+ */
+ public int getIndex() {
+ return mIndex;
+ }
+
+ /**
+ * Gets the page width in points (1/72").
+ *
+ * @return The width in points.
+ */
+ public int getWidth() {
+ return mWidth;
+ }
+
+ /**
+ * Gets the page height in points (1/72").
+ *
+ * @return The height in points.
+ */
+ public int getHeight() {
+ return mHeight;
+ }
+
+ /**
+ * Renders a page to a bitmap.
+ * <p>
+ * You may optionally specify a rectangular clip in the bitmap bounds. No rendering
+ * outside the clip will be performed, hence it is your responsibility to initialize
+ * the bitmap outside the clip.
+ * </p>
+ * <p>
+ * You may optionally specify a matrix to transform the content from page coordinates
+ * which are in points (1/72") to bitmap coordintates which are in pixels. If this
+ * matrix is not provided this method will apply a transformation that will fit the
+ * whole page to the destination clip if profided or the destination bitmap if no
+ * clip is provided.
+ * </p>
+ * <p>
+ * The clip and transformation are useful for implementing tile rendering where the
+ * destination bitmap contains a portion of the image, for example when zooming.
+ * Another useful application is for printing where the size of the bitmap holding
+ * the page is too large and a client can render the page in stripes.
+ * </p>
+ * <p>
+ * <strong>Note: </strong> The destination bitmap format must be
+ * {@link Config#ARGB_8888 ARGB}.
+ * </p>
+ * <p>
+ * <strong>Note: </strong> The optional transformation matrix must be affine as per
+ * {@link android.graphics.Matrix#isAffine()}. Hence, you can specify rotation, scaling,
+ * translation but not a perspective transformation.
+ * </p>
+ *
+ * @param destination Destination bitmap to which to render.
+ * @param destClip Optional clip in the bitmap bounds.
+ * @param transform Optional transformation to apply when rendering.
+ * @param renderMode The render mode.
+ *
+ * @see #RENDER_MODE_FOR_DISPLAY
+ * @see #RENDER_MODE_FOR_PRINT
+ */
+ public void render(@NonNull Bitmap destination, @Nullable Rect destClip,
+ @Nullable Matrix transform, @RenderMode int renderMode) {
+ if (destination.getConfig() != Config.ARGB_8888) {
+ throw new IllegalArgumentException("Unsupported pixel format");
+ }
+
+ if (destClip != null) {
+ if (destClip.left < 0 || destClip.top < 0
+ || destClip.right > destination.getWidth()
+ || destClip.bottom > destination.getHeight()) {
+ throw new IllegalArgumentException("destBounds not in destination");
+ }
+ }
+
+ if (transform != null && !transform.isAffine()) {
+ throw new IllegalArgumentException("transform not affine");
+ }
+
+ if (renderMode != RENDER_MODE_FOR_PRINT && renderMode != RENDER_MODE_FOR_DISPLAY) {
+ throw new IllegalArgumentException("Unsupported render mode");
+ }
+
+ if (renderMode == RENDER_MODE_FOR_PRINT && renderMode == RENDER_MODE_FOR_DISPLAY) {
+ throw new IllegalArgumentException("Only single render mode supported");
+ }
+
+ final int contentLeft = (destClip != null) ? destClip.left : 0;
+ final int contentTop = (destClip != null) ? destClip.top : 0;
+ final int contentRight = (destClip != null) ? destClip.right
+ : destination.getWidth();
+ final int contentBottom = (destClip != null) ? destClip.bottom
+ : destination.getHeight();
+
+ final long transformPtr = (transform != null) ? transform.native_instance : 0;
+
+ nativeRenderPage(mNativeDocument, mNativePage, destination.mNativeBitmap, contentLeft,
+ contentTop, contentRight, contentBottom, transformPtr, renderMode);
+ }
+
+ void close() {
+ nativeClosePage(mNativePage);
+ mNativePage = 0;
+ }
+ }
+
+ private static native long nativeCreate(int fd, long size);
+ private static native void nativeClose(long documentPtr);
+ private static native int nativeGetPageCount(long documentPtr);
+ private static native boolean nativeScaleForPrinting(long documentPtr);
+ private static native void nativeRenderPage(long documentPtr, long pagePtr, long destPtr,
+ int destLeft, int destTop, int destRight, int destBottom, long matrixPtr, int renderMode);
+ private static native long nativeOpenPageAndGetSize(long documentPtr, int pageIndex,
+ Point outSize);
+ private static native void nativeClosePage(long pagePtr);
+}
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index a033f86..83eedfb 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -27,31 +27,48 @@ namespace android {
namespace uirenderer {
/************************************************************
- * Base animator
+ * BaseRenderNodeAnimator
************************************************************/
-BaseAnimator::BaseAnimator()
- : mInterpolator(0)
- , mPlayState(PENDING)
+BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue)
+ : mFinalValue(finalValue)
+ , mDeltaValue(0)
+ , mFromValue(0)
+ , mInterpolator(0)
+ , mPlayState(NEEDS_START)
, mStartTime(0)
- , mDuration(300) {
-
+ , mDuration(300){
}
-BaseAnimator::~BaseAnimator() {
+BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
setInterpolator(NULL);
}
-void BaseAnimator::setInterpolator(Interpolator* interpolator) {
+void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) {
delete mInterpolator;
mInterpolator = interpolator;
}
-void BaseAnimator::setDuration(nsecs_t duration) {
+void BaseRenderNodeAnimator::setDuration(nsecs_t duration) {
mDuration = duration;
}
-bool BaseAnimator::animateFrame(TreeInfo& info) {
+void BaseRenderNodeAnimator::setStartValue(float value) {
+ LOG_ALWAYS_FATAL_IF(mPlayState != NEEDS_START,
+ "Cannot set the start value after the animator has started!");
+ mFromValue = value;
+ mDeltaValue = (mFinalValue - mFromValue);
+ mPlayState = PENDING;
+}
+
+void BaseRenderNodeAnimator::setupStartValueIfNecessary(RenderNode* target, TreeInfo& info) {
+ if (mPlayState == NEEDS_START) {
+ setStartValue(getValue(target));
+ mPlayState = PENDING;
+ }
+}
+
+bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) {
if (mPlayState == PENDING) {
mPlayState = RUNNING;
mStartTime = info.frameTimeMs;
@@ -59,7 +76,6 @@ bool BaseAnimator::animateFrame(TreeInfo& info) {
if (!mInterpolator) {
setInterpolator(Interpolator::createDefaultInterpolator());
}
- onAnimationStarted();
}
float fraction = 1.0f;
@@ -71,17 +87,16 @@ bool BaseAnimator::animateFrame(TreeInfo& info) {
}
}
fraction = mInterpolator->interpolate(fraction);
- onAnimationUpdated(fraction);
+ setValue(target, mFromValue + (mDeltaValue * fraction));
if (mPlayState == FINISHED) {
- onAnimationFinished();
callOnFinishedListener(info);
return true;
}
return false;
}
-void BaseAnimator::callOnFinishedListener(TreeInfo& info) {
+void BaseRenderNodeAnimator::callOnFinishedListener(TreeInfo& info) {
if (mListener.get()) {
if (!info.animationHook) {
mListener->onAnimationFinished(this);
@@ -92,70 +107,49 @@ void BaseAnimator::callOnFinishedListener(TreeInfo& info) {
}
/************************************************************
- * BaseRenderNodeAnimator
- ************************************************************/
-
-BaseRenderNodeAnimator::BaseRenderNodeAnimator(
- BaseRenderNodeAnimator::DeltaValueType deltaType, float delta)
- : mTarget(0)
- , mDeltaValueType(deltaType)
- , mDeltaValue(delta)
- , mFromValue(-1) {
-}
-
-bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) {
- mTarget = target;
- bool finished = animateFrame(info);
- mTarget = NULL;
- return finished;
-}
-
-void BaseRenderNodeAnimator::onAnimationStarted() {
- mFromValue = getValue();
-
- if (mDeltaValueType == BaseRenderNodeAnimator::ABSOLUTE) {
- mDeltaValue = (mDeltaValue - mFromValue);
- mDeltaValueType = BaseRenderNodeAnimator::DELTA;
- }
-}
-
-void BaseRenderNodeAnimator::onAnimationUpdated(float fraction) {
- float value = mFromValue + (mDeltaValue * fraction);
- setValue(value);
-}
-
-/************************************************************
* RenderPropertyAnimator
************************************************************/
+struct RenderPropertyAnimator::PropertyAccessors {
+ RenderNode::DirtyPropertyMask dirtyMask;
+ GetFloatProperty getter;
+ SetFloatProperty setter;
+};
+
// Maps RenderProperty enum to accessors
const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = {
- {&RenderProperties::getTranslationX, &RenderProperties::setTranslationX },
- {&RenderProperties::getTranslationY, &RenderProperties::setTranslationY },
- {&RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ },
- {&RenderProperties::getScaleX, &RenderProperties::setScaleX },
- {&RenderProperties::getScaleY, &RenderProperties::setScaleY },
- {&RenderProperties::getRotation, &RenderProperties::setRotation },
- {&RenderProperties::getRotationX, &RenderProperties::setRotationX },
- {&RenderProperties::getRotationY, &RenderProperties::setRotationY },
- {&RenderProperties::getX, &RenderProperties::setX },
- {&RenderProperties::getY, &RenderProperties::setY },
- {&RenderProperties::getZ, &RenderProperties::setZ },
- {&RenderProperties::getAlpha, &RenderProperties::setAlpha },
+ {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationX, &RenderProperties::setTranslationX },
+ {RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY, &RenderProperties::setTranslationY },
+ {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ },
+ {RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX },
+ {RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY },
+ {RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation },
+ {RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX },
+ {RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY },
+ {RenderNode::X, &RenderProperties::getX, &RenderProperties::setX },
+ {RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY },
+ {RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ },
+ {RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha },
};
-RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property,
- DeltaValueType deltaType, float deltaValue)
- : BaseRenderNodeAnimator(deltaType, deltaValue)
- , mPropertyAccess(PROPERTY_ACCESSOR_LUT[property]) {
+RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue)
+ : BaseRenderNodeAnimator(finalValue)
+ , mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {
+}
+
+void RenderPropertyAnimator::onAttached(RenderNode* target) {
+ if (target->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
+ setStartValue((target->stagingProperties().*mPropertyAccess->getter)());
+ }
+ (target->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
}
-float RenderPropertyAnimator::getValue() const {
- return (target()->animatorProperties().*mPropertyAccess.getter)();
+float RenderPropertyAnimator::getValue(RenderNode* target) const {
+ return (target->properties().*mPropertyAccess->getter)();
}
-void RenderPropertyAnimator::setValue(float value) {
- (target()->animatorProperties().*mPropertyAccess.setter)(value);
+void RenderPropertyAnimator::setValue(RenderNode* target, float value) {
+ (target->animatorProperties().*mPropertyAccess->setter)(value);
}
/************************************************************
@@ -163,16 +157,16 @@ void RenderPropertyAnimator::setValue(float value) {
************************************************************/
CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(
- CanvasPropertyPrimitive* property, DeltaValueType deltaType, float deltaValue)
- : BaseRenderNodeAnimator(deltaType, deltaValue)
+ CanvasPropertyPrimitive* property, float finalValue)
+ : BaseRenderNodeAnimator(finalValue)
, mProperty(property) {
}
-float CanvasPropertyPrimitiveAnimator::getValue() const {
+float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const {
return mProperty->value;
}
-void CanvasPropertyPrimitiveAnimator::setValue(float value) {
+void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) {
mProperty->value = value;
}
@@ -181,14 +175,13 @@ void CanvasPropertyPrimitiveAnimator::setValue(float value) {
************************************************************/
CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(
- CanvasPropertyPaint* property, PaintField field,
- DeltaValueType deltaType, float deltaValue)
- : BaseRenderNodeAnimator(deltaType, deltaValue)
+ CanvasPropertyPaint* property, PaintField field, float finalValue)
+ : BaseRenderNodeAnimator(finalValue)
, mProperty(property)
, mField(field) {
}
-float CanvasPropertyPaintAnimator::getValue() const {
+float CanvasPropertyPaintAnimator::getValue(RenderNode* target) const {
switch (mField) {
case STROKE_WIDTH:
return mProperty->value.getStrokeWidth();
@@ -204,7 +197,7 @@ static uint8_t to_uint8(float value) {
return static_cast<uint8_t>( c < 0 ? 0 : c > 255 ? 255 : c );
}
-void CanvasPropertyPaintAnimator::setValue(float value) {
+void CanvasPropertyPaintAnimator::setValue(RenderNode* target, float value) {
switch (mField) {
case STROKE_WIDTH:
mProperty->value.setStrokeWidth(value);
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index 52a1807..fe88cbf 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -33,16 +33,14 @@ class RenderProperties;
class AnimationListener : public VirtualLightRefBase {
public:
- ANDROID_API virtual void onAnimationFinished(BaseAnimator*) = 0;
+ ANDROID_API virtual void onAnimationFinished(BaseRenderNodeAnimator*) = 0;
protected:
ANDROID_API virtual ~AnimationListener() {}
};
-// Helper class to contain generic animator helpers
-class BaseAnimator : public VirtualLightRefBase {
- PREVENT_COPY_AND_ASSIGN(BaseAnimator);
+class BaseRenderNodeAnimator : public VirtualLightRefBase {
+ PREVENT_COPY_AND_ASSIGN(BaseRenderNodeAnimator);
public:
-
ANDROID_API void setInterpolator(Interpolator* interpolator);
ANDROID_API void setDuration(nsecs_t durationInMs);
ANDROID_API nsecs_t duration() { return mDuration; }
@@ -50,31 +48,38 @@ public:
mListener = listener;
}
+ ANDROID_API virtual void onAttached(RenderNode* target) {}
+
+ // Guaranteed to happen before the staging push
+ void setupStartValueIfNecessary(RenderNode* target, TreeInfo& info);
+
+ bool animate(RenderNode* target, TreeInfo& info);
+
bool isFinished() { return mPlayState == FINISHED; }
+ float finalValue() { return mFinalValue; }
protected:
- BaseAnimator();
- virtual ~BaseAnimator();
-
- // This is the main animation entrypoint that subclasses should call
- // to generate the onAnimation* lifecycle events
- // Returns true if the animation has finished, false otherwise
- bool animateFrame(TreeInfo& info);
+ BaseRenderNodeAnimator(float finalValue);
+ virtual ~BaseRenderNodeAnimator();
- // Called when PlayState switches from PENDING to RUNNING
- virtual void onAnimationStarted() {}
- virtual void onAnimationUpdated(float fraction) = 0;
- virtual void onAnimationFinished() {}
+ void setStartValue(float value);
+ virtual float getValue(RenderNode* target) const = 0;
+ virtual void setValue(RenderNode* target, float value) = 0;
private:
void callOnFinishedListener(TreeInfo& info);
enum PlayState {
+ NEEDS_START,
PENDING,
RUNNING,
FINISHED,
};
+ float mFinalValue;
+ float mDeltaValue;
+ float mFromValue;
+
Interpolator* mInterpolator;
PlayState mPlayState;
long mStartTime;
@@ -83,42 +88,6 @@ private:
sp<AnimationListener> mListener;
};
-class BaseRenderNodeAnimator : public BaseAnimator {
-public:
- // Since the UI thread doesn't necessarily know what the current values
- // actually are and thus can't do the calculations, this is used to inform
- // the animator how to lazy-resolve the input value
- enum DeltaValueType {
- // The delta value represents an absolute value endpoint
- // mDeltaValue needs to be recalculated to be mDelta = (mDelta - fromValue)
- // in onAnimationStarted()
- ABSOLUTE = 0,
- // The final value represents an offset from the current value
- // No recalculation is needed
- DELTA,
- };
-
- bool animate(RenderNode* target, TreeInfo& info);
-
-protected:
- BaseRenderNodeAnimator(DeltaValueType deltaType, float deltaValue);
-
- RenderNode* target() const { return mTarget; }
- virtual float getValue() const = 0;
- virtual void setValue(float value) = 0;
-
-private:
- virtual void onAnimationStarted();
- virtual void onAnimationUpdated(float fraction);
-
- // mTarget is only valid inside animate()
- RenderNode* mTarget;
-
- BaseRenderNodeAnimator::DeltaValueType mDeltaValueType;
- float mDeltaValue;
- float mFromValue;
-};
-
class RenderPropertyAnimator : public BaseRenderNodeAnimator {
public:
enum RenderProperty {
@@ -136,23 +105,20 @@ public:
ALPHA,
};
- ANDROID_API RenderPropertyAnimator(RenderProperty property,
- DeltaValueType deltaType, float deltaValue);
+ ANDROID_API RenderPropertyAnimator(RenderProperty property, float finalValue);
+
+ ANDROID_API virtual void onAttached(RenderNode* target);
protected:
- ANDROID_API virtual float getValue() const;
- ANDROID_API virtual void setValue(float value);
+ virtual float getValue(RenderNode* target) const;
+ virtual void setValue(RenderNode* target, float value);
private:
typedef void (RenderProperties::*SetFloatProperty)(float value);
typedef float (RenderProperties::*GetFloatProperty)() const;
- struct PropertyAccessors {
- GetFloatProperty getter;
- SetFloatProperty setter;
- };
-
- PropertyAccessors mPropertyAccess;
+ struct PropertyAccessors;
+ const PropertyAccessors* mPropertyAccess;
static const PropertyAccessors PROPERTY_ACCESSOR_LUT[];
};
@@ -160,10 +126,10 @@ private:
class CanvasPropertyPrimitiveAnimator : public BaseRenderNodeAnimator {
public:
ANDROID_API CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property,
- DeltaValueType deltaType, float deltaValue);
+ float finalValue);
protected:
- ANDROID_API virtual float getValue() const;
- ANDROID_API virtual void setValue(float value);
+ virtual float getValue(RenderNode* target) const;
+ virtual void setValue(RenderNode* target, float value);
private:
sp<CanvasPropertyPrimitive> mProperty;
};
@@ -176,10 +142,10 @@ public:
};
ANDROID_API CanvasPropertyPaintAnimator(CanvasPropertyPaint* property,
- PaintField field, DeltaValueType deltaType, float deltaValue);
+ PaintField field, float finalValue);
protected:
- ANDROID_API virtual float getValue() const;
- ANDROID_API virtual void setValue(float value);
+ virtual float getValue(RenderNode* target) const;
+ virtual void setValue(RenderNode* target, float value);
private:
sp<CanvasPropertyPaint> mProperty;
PaintField mField;
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 45b6624..3016814 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -28,6 +28,7 @@
#include "DeferredDisplayList.h"
#include "DisplayListOp.h"
#include "OpenGLRenderer.h"
+#include "utils/MathUtils.h"
#if DEBUG_DEFER
#define DEFER_LOGD(...) ALOGD(__VA_ARGS__)
@@ -146,10 +147,6 @@ private:
mergeid_t mMergeId;
};
-// compare alphas approximately, with a small margin
-#define NEQ_FALPHA(lhs, rhs) \
- fabs((float)lhs - (float)rhs) > 0.001f
-
class MergingDrawBatch : public DrawBatch {
public:
MergingDrawBatch(DeferInfo& deferInfo, int width, int height) :
@@ -196,7 +193,11 @@ public:
const DeferredDisplayState* lhs = state;
const DeferredDisplayState* rhs = mOps[0].state;
- if (NEQ_FALPHA(lhs->mAlpha, rhs->mAlpha)) return false;
+ if (!MathUtils::areEqual(lhs->mAlpha, rhs->mAlpha)) return false;
+
+ // Identical round rect clip state means both ops will clip in the same way, or not at all.
+ // As the state objects are const, we can compare their pointers to determine mergeability
+ if (lhs->mRoundRectClipState != rhs->mRoundRectClipState) return false;
/* Clipping compatibility check
*
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index fca3588..48489c2 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -64,6 +64,7 @@ public:
mat4 mMatrix;
DrawModifiers mDrawModifiers;
float mAlpha;
+ const RoundRectClipState* mRoundRectClipState;
};
class OpStatePair {
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 4df97e6..7993c0f 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -711,6 +711,7 @@ int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float
mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
+ mSnapshot->roundRectClipState = NULL;
}
}
@@ -844,6 +845,7 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
+ mSnapshot->roundRectClipState = NULL;
endTiling();
debugOverdraw(false, false);
@@ -872,8 +874,6 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
// Change the ortho projection
glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
-
-
return true;
}
@@ -892,7 +892,7 @@ void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& resto
bool clipRequired = false;
calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
- &clipRequired, false); // safely ignore return, should never be rejected
+ &clipRequired, NULL, false); // safely ignore return, should never be rejected
mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
if (fboLayer) {
@@ -1367,6 +1367,9 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDef
state.mMatrix.load(*currentMatrix);
state.mDrawModifiers = mDrawModifiers;
state.mAlpha = currentSnapshot()->alpha;
+
+ // always store/restore, since it's just a pointer
+ state.mRoundRectClipState = currentSnapshot()->roundRectClipState;
return false;
}
@@ -1374,6 +1377,7 @@ void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool
setMatrix(state.mMatrix);
mSnapshot->alpha = state.mAlpha;
mDrawModifiers = state.mDrawModifiers;
+ mSnapshot->roundRectClipState = state.mRoundRectClipState;
if (state.mClipValid && !skipClipRestore) {
mSnapshot->setClip(state.mClip.left, state.mClip.top,
@@ -1449,7 +1453,7 @@ void OpenGLRenderer::setStencilFromClip() {
mCaches.stencil.enableWrite();
- // Clear the stencil but first make sure we restrict drawing
+ // Clear and update the stencil, but first make sure we restrict drawing
// to the region's bounds
bool resetScissor = mCaches.enableScissor();
if (resetScissor) {
@@ -1457,7 +1461,10 @@ void OpenGLRenderer::setStencilFromClip() {
setScissorFromClip();
}
mCaches.stencil.clear();
- if (resetScissor) mCaches.disableScissor();
+
+ // stash and disable the outline clip state, since stencil doesn't account for outline
+ bool storedSkipOutlineClip = mSkipOutlineClip;
+ mSkipOutlineClip = true;
SkPaint paint;
paint.setColor(0xff000000);
@@ -1470,6 +1477,8 @@ void OpenGLRenderer::setStencilFromClip() {
// The last parameter is important: we are not drawing in the color buffer
// so we don't want to dirty the current layer, if any
drawRegionRects(*(currentSnapshot()->clipRegion), paint, false);
+ if (resetScissor) mCaches.disableScissor();
+ mSkipOutlineClip = storedSkipOutlineClip;
mCaches.stencil.enableTest();
@@ -1494,7 +1503,6 @@ void OpenGLRenderer::setStencilFromClip() {
*/
bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right, float bottom,
const SkPaint* paint) {
- bool clipRequired = false;
bool snapOut = paint && paint->isAntiAlias();
if (paint && paint->getStyle() != SkPaint::kFill_Style) {
@@ -1505,13 +1513,17 @@ bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right,
bottom += outset;
}
- if (calculateQuickRejectForScissor(left, top, right, bottom, &clipRequired, snapOut)) {
+ bool clipRequired = false;
+ bool roundRectClipRequired = false;
+ if (calculateQuickRejectForScissor(left, top, right, bottom,
+ &clipRequired, &roundRectClipRequired, snapOut)) {
return true;
}
if (!isRecording()) {
// not quick rejected, so enable the scissor if clipRequired
mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
+ mSkipOutlineClip = !roundRectClipRequired;
}
return false;
}
@@ -1668,6 +1680,18 @@ void OpenGLRenderer::setupDrawBlending(const SkPaint* paint, bool blend, bool sw
void OpenGLRenderer::setupDrawProgram() {
useProgram(mCaches.programCache.get(mDescription));
+ if (mDescription.hasRoundRectClip) {
+ // TODO: avoid doing this repeatedly, stashing state pointer in program
+ const RoundRectClipState* state = mSnapshot->roundRectClipState;
+ const Rect& innerRect = state->outlineInnerRect;
+ glUniform4f(mCaches.currentProgram->getUniform("roundRectInnerRectLTRB"),
+ innerRect.left, innerRect.top,
+ innerRect.right, innerRect.bottom);
+ glUniform1f(mCaches.currentProgram->getUniform("roundRectRadius"),
+ state->outlineRadius);
+ glUniformMatrix4fv(mCaches.currentProgram->getUniform("roundRectInvTransform"),
+ 1, GL_FALSE, &state->matrix.data[0]);
+ }
}
void OpenGLRenderer::setupDrawDirtyRegionsDisabled() {
@@ -2902,7 +2926,7 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
bool clipRequired = false;
const bool rejected = calculateQuickRejectForScissor(x, y,
- x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired, false);
+ x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired, NULL, false);
if (rejected) {
if (transform && !transform->isIdentity()) {
@@ -3433,6 +3457,13 @@ void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, f
void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
ProgramDescription& description, bool swapSrcDst) {
+
+ if (mSnapshot->roundRectClipState != NULL /*&& !mSkipOutlineClip*/) {
+ blend = true;
+ mDescription.hasRoundRectClip = true;
+ }
+ mSkipOutlineClip = true;
+
if (mCountOverdraw) {
if (!mCaches.blend) glEnable(GL_BLEND);
if (mCaches.lastSrcMode != GL_ONE || mCaches.lastDstMode != GL_ONE) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index b58b817..f70ae58 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -993,6 +993,8 @@ private:
bool mCountOverdraw;
float mOverdraw;
+ bool mSkipOutlineClip;
+
friend class DisplayListRenderer;
friend class Layer;
friend class TextSetupFunctor;
diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h
index 530be30..5c24335 100644
--- a/libs/hwui/Outline.h
+++ b/libs/hwui/Outline.h
@@ -58,11 +58,24 @@ public:
mShouldClip = clip;
}
+ bool getShouldClip() const {
+ return mShouldClip;
+ }
+
bool willClip() const {
// only round rect outlines can be used for clipping
return mShouldClip && (mType == kOutlineType_RoundRect);
}
+ bool getAsRoundRect(Rect* outRect, float* outRadius) const {
+ if (mType == kOutlineType_RoundRect) {
+ outRect->set(mBounds);
+ *outRadius = mRadius;
+ return true;
+ }
+ return false;
+ }
+
const SkPath* getPath() const {
if (mType == kOutlineType_None) return NULL;
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 33c91b3..3e191d0 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -45,17 +45,18 @@ namespace uirenderer {
#define COLOR_COMPONENT_THRESHOLD 1.0f
#define COLOR_COMPONENT_INV_THRESHOLD 0.0f
-#define PROGRAM_KEY_TEXTURE 0x1
-#define PROGRAM_KEY_A8_TEXTURE 0x2
-#define PROGRAM_KEY_BITMAP 0x4
-#define PROGRAM_KEY_GRADIENT 0x8
-#define PROGRAM_KEY_BITMAP_FIRST 0x10
-#define PROGRAM_KEY_COLOR_MATRIX 0x20
-#define PROGRAM_KEY_COLOR_BLEND 0x40
-#define PROGRAM_KEY_BITMAP_NPOT 0x80
-#define PROGRAM_KEY_SWAP_SRC_DST 0x2000
-
-#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
+#define PROGRAM_KEY_TEXTURE 0x01
+#define PROGRAM_KEY_A8_TEXTURE 0x02
+#define PROGRAM_KEY_BITMAP 0x04
+#define PROGRAM_KEY_GRADIENT 0x08
+#define PROGRAM_KEY_BITMAP_FIRST 0x10
+#define PROGRAM_KEY_COLOR_MATRIX 0x20
+#define PROGRAM_KEY_COLOR_BLEND 0x40
+#define PROGRAM_KEY_BITMAP_NPOT 0x80
+
+#define PROGRAM_KEY_SWAP_SRC_DST 0x2000
+
+#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800
// Encode the xfermodes on 6 bits
@@ -83,6 +84,7 @@ namespace uirenderer {
#define PROGRAM_HAS_DEBUG_HIGHLIGHT 42
#define PROGRAM_EMULATE_STENCIL 43
+#define PROGRAM_HAS_ROUND_RECT_CLIP 44
///////////////////////////////////////////////////////////////////////////////
// Types
@@ -158,6 +160,7 @@ struct ProgramDescription {
bool hasDebugHighlight;
bool emulateStencil;
+ bool hasRoundRectClip;
/**
* Resets this description. All fields are reset back to the default
@@ -198,6 +201,8 @@ struct ProgramDescription {
gamma = 2.2f;
hasDebugHighlight = false;
+ emulateStencil = false;
+ hasRoundRectClip = false;
}
/**
@@ -264,6 +269,7 @@ struct ProgramDescription {
if (hasColors) key |= programid(0x1) << PROGRAM_HAS_COLORS;
if (hasDebugHighlight) key |= programid(0x1) << PROGRAM_HAS_DEBUG_HIGHLIGHT;
if (emulateStencil) key |= programid(0x1) << PROGRAM_EMULATE_STENCIL;
+ if (hasRoundRectClip) key |= programid(0x1) << PROGRAM_HAS_ROUND_RECT_CLIP;
return key;
}
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 6d50410..f451690 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -58,6 +58,8 @@ const char* gVS_Header_Uniforms_HasGradient =
const char* gVS_Header_Uniforms_HasBitmap =
"uniform mat4 textureTransform;\n"
"uniform mediump vec2 textureDimension;\n";
+const char* gVS_Header_Uniforms_HasRoundRectClip =
+ "uniform mat4 roundRectInvTransform;\n";
const char* gVS_Header_Varyings_HasTexture =
"varying vec2 outTexCoords;\n";
const char* gVS_Header_Varyings_HasColors =
@@ -85,6 +87,8 @@ const char* gVS_Header_Varyings_HasGradient[6] = {
"varying highp vec2 sweep;\n"
"varying vec2 ditherTexCoords;\n",
};
+const char* gVS_Header_Varyings_HasRoundRectClip =
+ "varying vec2 roundRectPos;\n";
const char* gVS_Main =
"\nvoid main(void) {\n";
const char* gVS_Main_OutTexCoords =
@@ -115,9 +119,12 @@ const char* gVS_Main_OutGradient[6] = {
const char* gVS_Main_OutBitmapTexCoords =
" outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
const char* gVS_Main_Position =
- " gl_Position = projection * transform * position;\n";
+ " vec4 transformedPosition = projection * transform * position;\n"
+ " gl_Position = transformedPosition;\n";
const char* gVS_Main_AAVertexShape =
" alpha = vtxAlpha;\n";
+const char* gVS_Main_HasRoundRectClip =
+ " roundRectPos = (roundRectInvTransform * transformedPosition).xy;\n";
const char* gVS_Footer =
"}\n\n";
@@ -160,6 +167,10 @@ const char* gFS_Uniforms_ColorOp[3] = {
const char* gFS_Uniforms_Gamma =
"uniform float gamma;\n";
+const char* gFS_Uniforms_HasRoundRectClip =
+ "uniform vec4 roundRectInnerRectLTRB;\n"
+ "uniform float roundRectRadius;\n";
+
const char* gFS_Main =
"\nvoid main(void) {\n"
" lowp vec4 fragColor;\n";
@@ -318,6 +329,15 @@ const char* gFS_Main_ApplyColorOp[3] = {
// PorterDuff
" fragColor = blendColors(colorBlend, fragColor);\n"
};
+
+// Note: LTRB -> xyzw
+const char* gFS_Main_FragColor_HasRoundRectClip =
+ " mediump vec2 fragToLT = roundRectInnerRectLTRB.xy - roundRectPos;\n"
+ " mediump vec2 fragFromRB = roundRectPos - roundRectInnerRectLTRB.zw;\n"
+ " mediump vec2 dist = max(max(fragToLT, fragFromRB), vec2(0.0, 0.0));\n"
+ " mediump float linearDist = roundRectRadius - length(dist);\n"
+ " gl_FragColor *= clamp(linearDist, 0.0, 1.0);\n";
+
const char* gFS_Main_DebugHighlight =
" gl_FragColor.rgb = vec3(0.0, gl_FragColor.a, 0.0);\n";
const char* gFS_Main_EmulateStencil =
@@ -462,6 +482,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
if (description.hasBitmap) {
shader.append(gVS_Header_Uniforms_HasBitmap);
}
+ if (description.hasRoundRectClip) {
+ shader.append(gVS_Header_Uniforms_HasRoundRectClip);
+ }
// Varyings
if (description.hasTexture || description.hasExternalTexture) {
shader.append(gVS_Header_Varyings_HasTexture);
@@ -478,6 +501,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
if (description.hasBitmap) {
shader.append(gVS_Header_Varyings_HasBitmap);
}
+ if (description.hasRoundRectClip) {
+ shader.append(gVS_Header_Varyings_HasRoundRectClip);
+ }
// Begin the shader
shader.append(gVS_Main); {
@@ -500,6 +526,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
if (description.hasGradient) {
shader.append(gVS_Main_OutGradient[gradientIndex(description)]);
}
+ if (description.hasRoundRectClip) {
+ shader.append(gVS_Main_HasRoundRectClip);
+ }
}
// End the shader
shader.append(gVS_Footer);
@@ -546,6 +575,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
if (description.hasBitmap) {
shader.append(gVS_Header_Varyings_HasBitmap);
}
+ if (description.hasRoundRectClip) {
+ shader.append(gVS_Header_Varyings_HasRoundRectClip);
+ }
// Uniforms
int modulateOp = MODULATE_OP_NO_MODULATE;
@@ -568,11 +600,18 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
if (description.hasGammaCorrection) {
shader.append(gFS_Uniforms_Gamma);
}
+ if (description.hasRoundRectClip) {
+ shader.append(gFS_Uniforms_HasRoundRectClip);
+ }
// Optimization for common cases
- if (!description.isAA && !blendFramebuffer && !description.hasColors &&
- description.colorOp == ProgramDescription::kColorNone &&
- !description.hasDebugHighlight && !description.emulateStencil) {
+ if (!description.isAA
+ && !blendFramebuffer
+ && !description.hasColors
+ && description.colorOp == ProgramDescription::kColorNone
+ && !description.hasDebugHighlight
+ && !description.emulateStencil
+ && !description.hasRoundRectClip) {
bool fast = false;
const bool noShader = !description.hasGradient && !description.hasBitmap;
@@ -722,6 +761,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
if (description.hasColors) {
shader.append(gFS_Main_FragColor_HasColors);
}
+ if (description.hasRoundRectClip) {
+ shader.append(gFS_Main_FragColor_HasRoundRectClip);
+ }
if (description.hasDebugHighlight) {
shader.append(gFS_Main_DebugHighlight);
}
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index f38d8b7..2ddbbd7 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -234,7 +234,7 @@ public:
bottom = ceilf(bottom);
}
- void dump(const char* label) const {
+ void dump(const char* label = NULL) const {
ALOGD("%s[l=%f t=%f r=%f b=%f]", label ? label : "Rect", left, top, right, bottom);
}
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index fba482d..f0645a9 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -53,7 +53,7 @@ void RenderNode::outputLogBuffer(int fd) {
}
RenderNode::RenderNode()
- : mNeedsPropertiesSync(false)
+ : mDirtyPropertyFields(0)
, mNeedsDisplayListDataSync(false)
, mDisplayListData(0)
, mStagingDisplayListData(0)
@@ -109,23 +109,37 @@ void RenderNode::prepareTreeImpl(TreeInfo& info) {
prepareSubTree(info, mDisplayListData);
}
-static bool is_finished(const sp<BaseRenderNodeAnimator>& animator) {
- return animator->isFinished();
-}
+class PushAnimatorsFunctor {
+public:
+ PushAnimatorsFunctor(RenderNode* target, TreeInfo& info)
+ : mTarget(target), mInfo(info) {}
-void RenderNode::pushStagingChanges(TreeInfo& info) {
- if (mNeedsPropertiesSync) {
- mNeedsPropertiesSync = false;
- mProperties = mStagingProperties;
+ bool operator() (const sp<BaseRenderNodeAnimator>& animator) {
+ animator->setupStartValueIfNecessary(mTarget, mInfo);
+ return animator->isFinished();
}
+private:
+ RenderNode* mTarget;
+ TreeInfo& mInfo;
+};
+
+void RenderNode::pushStagingChanges(TreeInfo& info) {
+ // Push the animators first so that setupStartValueIfNecessary() is called
+ // before properties() is trampled by stagingProperties(), as they are
+ // required by some animators.
if (mNeedsAnimatorsSync) {
mAnimators.resize(mStagingAnimators.size());
std::vector< sp<BaseRenderNodeAnimator> >::iterator it;
+ PushAnimatorsFunctor functor(this, info);
// hint: this means copy_if_not()
it = std::remove_copy_if(mStagingAnimators.begin(), mStagingAnimators.end(),
- mAnimators.begin(), is_finished);
+ mAnimators.begin(), functor);
mAnimators.resize(std::distance(mAnimators.begin(), it));
}
+ if (mDirtyPropertyFields) {
+ mDirtyPropertyFields = 0;
+ mProperties = mStagingProperties;
+ }
if (mNeedsDisplayListDataSync) {
mNeedsDisplayListDataSync = false;
// Do a push pass on the old tree to handle freeing DisplayListData
@@ -144,7 +158,7 @@ public:
AnimateFunctor(RenderNode* target, TreeInfo& info)
: mTarget(target), mInfo(info) {}
- bool operator() (sp<BaseRenderNodeAnimator>& animator) {
+ bool operator() (const sp<BaseRenderNodeAnimator>& animator) {
return animator->animate(mTarget, mInfo);
}
private:
@@ -653,6 +667,10 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
bool quickRejected = properties().getClipToBounds()
&& renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight());
if (!quickRejected) {
+ if (mProperties.getOutline().willClip()) {
+ renderer.setClippingOutline(alloc, &(mProperties.getOutline()));
+ }
+
Vector<ZDrawDisplayListOpPair> zTranslatedNodes;
buildZSortedChildList(zTranslatedNodes);
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index bc62ee1..1811a7b 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -82,6 +82,22 @@ class DrawDisplayListOp;
*/
class RenderNode : public VirtualLightRefBase {
public:
+ enum DirtyPropertyMask {
+ GENERIC = 1 << 1,
+ TRANSLATION_X = 1 << 2,
+ TRANSLATION_Y = 1 << 3,
+ TRANSLATION_Z = 1 << 4,
+ SCALE_X = 1 << 5,
+ SCALE_Y = 1 << 6,
+ ROTATION = 1 << 7,
+ ROTATION_X = 1 << 8,
+ ROTATION_Y = 1 << 9,
+ X = 1 << 10,
+ Y = 1 << 11,
+ Z = 1 << 12,
+ ALPHA = 1 << 13,
+ };
+
ANDROID_API RenderNode();
ANDROID_API virtual ~RenderNode();
@@ -123,6 +139,14 @@ public:
}
}
+ bool isPropertyFieldDirty(DirtyPropertyMask field) const {
+ return mDirtyPropertyFields & field;
+ }
+
+ void setPropertyFieldsDirty(uint32_t fields) {
+ mDirtyPropertyFields |= fields;
+ }
+
const RenderProperties& properties() {
return mProperties;
}
@@ -136,7 +160,6 @@ public:
}
RenderProperties& mutateStagingProperties() {
- mNeedsPropertiesSync = true;
return mStagingProperties;
}
@@ -152,6 +175,7 @@ public:
// UI thread only!
ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
+ animator->onAttached(this);
mStagingAnimators.insert(animator);
mNeedsAnimatorsSync = true;
}
@@ -227,7 +251,7 @@ private:
String8 mName;
- bool mNeedsPropertiesSync;
+ uint32_t mDirtyPropertyFields;
RenderProperties mProperties;
RenderProperties mStagingProperties;
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 029b56d..80f7eca 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -20,6 +20,8 @@
#include <SkCanvas.h>
+#include "utils/MathUtils.h"
+
namespace android {
namespace uirenderer {
@@ -34,7 +36,8 @@ Snapshot::Snapshot()
, fbo(0)
, invisible(false)
, empty(false)
- , alpha(1.0f) {
+ , alpha(1.0f)
+ , roundRectClipState(NULL) {
transform = &mTransformRoot;
clipRect = &mClipRectRoot;
region = NULL;
@@ -53,8 +56,8 @@ Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags)
, invisible(s->invisible)
, empty(false)
, alpha(s->alpha)
+ , roundRectClipState(s->roundRectClipState)
, mViewportData(s->mViewportData) {
-
if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
mTransformRoot.load(*s->transform);
transform = &mTransformRoot;
@@ -204,6 +207,49 @@ void Snapshot::resetTransform(float x, float y, float z) {
}
///////////////////////////////////////////////////////////////////////////////
+// Clipping outline
+///////////////////////////////////////////////////////////////////////////////
+
+void Snapshot::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
+ Rect bounds;
+ float radius;
+ if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
+
+ if (!MathUtils::isPositive(radius)) return; // leave clipping up to rect clipping
+
+ RoundRectClipState* state = new (allocator) RoundRectClipState;
+
+ // store the inverse drawing matrix
+ Matrix4 outlineDrawingMatrix;
+ outlineDrawingMatrix.load(getOrthoMatrix());
+ outlineDrawingMatrix.multiply(*transform);
+ state->matrix.loadInverse(outlineDrawingMatrix);
+
+ // compute area under rounded corners - only draws overlapping these rects need to be clipped
+ for (int i = 0 ; i < 4; i++) {
+ state->dangerRects[i] = bounds;
+ }
+ state->dangerRects[0].bottom = state->dangerRects[1].bottom = bounds.top + radius;
+ state->dangerRects[0].right = state->dangerRects[2].right = bounds.left + radius;
+ state->dangerRects[1].left = state->dangerRects[3].left = bounds.right - radius;
+ state->dangerRects[2].top = state->dangerRects[3].top = bounds.bottom - radius;
+ for (int i = 0; i < 4; i++) {
+ transform->mapRect(state->dangerRects[i]);
+
+ // round danger rects out as though they are AA geometry (since they essentially are)
+ state->dangerRects[i].snapGeometryToPixelBoundaries(true);
+ }
+
+ // store RR area
+ bounds.inset(radius);
+ state->outlineInnerRect = bounds;
+ state->outlineRadius = radius;
+
+ // store as immutable so, for this frame, pointer uniquely identifies this bundle of shader info
+ roundRectClipState = state;
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Queries
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index e9ab1ff..435736c 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -20,6 +20,7 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+#include <utils/LinearAllocator.h>
#include <utils/RefBase.h>
#include <ui/Region.h>
@@ -27,12 +28,40 @@
#include "Layer.h"
#include "Matrix.h"
+#include "Outline.h"
#include "Rect.h"
+#include "utils/Macros.h"
namespace android {
namespace uirenderer {
/**
+ * Temporary structure holding information for a single outline clip.
+ *
+ * These structures are treated as immutable once created, and only exist for a single frame, which
+ * is why they may only be allocated with a LinearAllocator.
+ */
+class RoundRectClipState {
+public:
+ /** static void* operator new(size_t size); PURPOSELY OMITTED, allocator only **/
+ static void* operator new(size_t size, LinearAllocator& allocator) {
+ return allocator.alloc(size);
+ }
+
+ bool areaRequiresRoundRectClip(const Rect& rect) const {
+ return rect.intersects(dangerRects[0])
+ || rect.intersects(dangerRects[1])
+ || rect.intersects(dangerRects[2])
+ || rect.intersects(dangerRects[3]);
+ }
+
+ Matrix4 matrix;
+ Rect dangerRects[4];
+ Rect outlineInnerRect;
+ float outlineRadius;
+};
+
+/**
* A snapshot holds information about the current state of the rendering
* surface. A snapshot is usually created whenever the user calls save()
* and discarded when the user calls restore(). Once a snapshot is created,
@@ -133,6 +162,11 @@ public:
const Matrix4& getOrthoMatrix() const { return mViewportData.mOrthoMatrix; }
/**
+ * Sets (and replaces) the current clipping outline
+ */
+ void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
+
+ /**
* Indicates whether this snapshot should be ignored. A snapshot
* is typicalled ignored if its layer is invisible or empty.
*/
@@ -225,6 +259,14 @@ public:
*/
float alpha;
+ /**
+ * Current clipping round rect.
+ *
+ * Points to data not owned by the snapshot, and may only be replaced by subsequent RR clips,
+ * never modified.
+ */
+ const RoundRectClipState* roundRectClipState;
+
void dump() const;
private:
diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp
index aa83e20..7d299f0 100644
--- a/libs/hwui/StatefulBaseRenderer.cpp
+++ b/libs/hwui/StatefulBaseRenderer.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "OpenGLRenderer"
+
#include <SkCanvas.h>
#include "StatefulBaseRenderer.h"
@@ -180,6 +182,10 @@ bool StatefulBaseRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
return !mSnapshot->clipRect->isEmpty();
}
+void StatefulBaseRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
+ mSnapshot->setClippingOutline(allocator, outline);
+}
+
///////////////////////////////////////////////////////////////////////////////
// Quick Rejection
///////////////////////////////////////////////////////////////////////////////
@@ -195,7 +201,9 @@ bool StatefulBaseRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
* See Rect::snapGeometryToPixelBoundaries()
*/
bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top,
- float right, float bottom, bool* clipRequired, bool snapOut) const {
+ float right, float bottom,
+ bool* clipRequired, bool* roundRectClipRequired,
+ bool snapOut) const {
if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
return true;
}
@@ -210,7 +218,15 @@ bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top,
if (!clipRect.intersects(r)) return true;
// clip is required if geometry intersects clip rect
- if (clipRequired) *clipRequired = !clipRect.contains(r);
+ if (clipRequired) {
+ *clipRequired = !clipRect.contains(r);
+ }
+
+ // round rect clip is required if RR clip exists, and geometry intersects its corners
+ if (roundRectClipRequired) {
+ *roundRectClipRequired = mSnapshot->roundRectClipState != NULL
+ && mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r);
+ }
return false;
}
diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h
index 9fbf2ca..2e7f279 100644
--- a/libs/hwui/StatefulBaseRenderer.h
+++ b/libs/hwui/StatefulBaseRenderer.h
@@ -88,6 +88,14 @@ public:
virtual bool clipPath(const SkPath* path, SkRegion::Op op);
virtual bool clipRegion(const SkRegion* region, SkRegion::Op op);
+ /**
+ * Does not support different clipping Ops (that is, every call to setClippingOutline is
+ * effectively using SkRegion::kReplaceOp)
+ *
+ * The clipping outline is independent from the regular clip.
+ */
+ void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
+
protected:
const Rect& getRenderTargetClipBounds() const { return mSnapshot->getRenderTargetClip(); }
@@ -106,7 +114,7 @@ protected:
// Clip
bool calculateQuickRejectForScissor(float left, float top, float right, float bottom,
- bool* clipRequired, bool snapOut) const;
+ bool* clipRequired, bool* roundRectClipRequired, bool snapOut) const;
/**
* Called just after a restore has occurred. The 'removed' snapshot popped from the stack,
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index fc5994c..d4a23b8 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -21,12 +21,12 @@
namespace android {
namespace uirenderer {
-class BaseAnimator;
+class BaseRenderNodeAnimator;
class AnimationListener;
class AnimationHook {
public:
- virtual void callOnFinished(BaseAnimator* animator, AnimationListener* listener) = 0;
+ virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) = 0;
protected:
~AnimationHook() {}
};
diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h
index 1a7082b..997acde2 100644
--- a/libs/hwui/utils/MathUtils.h
+++ b/libs/hwui/utils/MathUtils.h
@@ -34,6 +34,10 @@ public:
return value >= gNonZeroEpsilon;
}
+ inline static bool areEqual(float valueA, float valueB) {
+ return isZero(valueA - valueB);
+ }
+
inline static int min(int a, int b) {
return a < b ? a : b;
}
diff --git a/media/java/android/media/TtmlRenderer.java b/media/java/android/media/TtmlRenderer.java
new file mode 100644
index 0000000..0309334
--- /dev/null
+++ b/media/java/android/media/TtmlRenderer.java
@@ -0,0 +1,751 @@
+/*
+ * 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.media;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.media.SubtitleTrack.RenderingWidget.OnChangedListener;
+import android.text.Layout.Alignment;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup.LayoutParams;
+import android.view.accessibility.CaptioningManager;
+import android.view.accessibility.CaptioningManager.CaptionStyle;
+import android.view.accessibility.CaptioningManager.CaptioningChangeListener;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.widget.SubtitleView;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.TreeSet;
+import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+/** @hide */
+public class TtmlRenderer extends SubtitleController.Renderer {
+ private final Context mContext;
+
+ private static final String MEDIA_MIMETYPE_TEXT_TTML = "application/ttml+xml";
+
+ private TtmlRenderingWidget mRenderingWidget;
+
+ public TtmlRenderer(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public boolean supports(MediaFormat format) {
+ if (format.containsKey(MediaFormat.KEY_MIME)) {
+ return format.getString(MediaFormat.KEY_MIME).equals(MEDIA_MIMETYPE_TEXT_TTML);
+ }
+ return false;
+ }
+
+ @Override
+ public SubtitleTrack createTrack(MediaFormat format) {
+ if (mRenderingWidget == null) {
+ mRenderingWidget = new TtmlRenderingWidget(mContext);
+ }
+ return new TtmlTrack(mRenderingWidget, format);
+ }
+}
+
+/**
+ * A class which provides utillity methods for TTML parsing.
+ *
+ * @hide
+ */
+final class TtmlUtils {
+ public static final String TAG_TT = "tt";
+ public static final String TAG_HEAD = "head";
+ public static final String TAG_BODY = "body";
+ public static final String TAG_DIV = "div";
+ public static final String TAG_P = "p";
+ public static final String TAG_SPAN = "span";
+ public static final String TAG_BR = "br";
+ public static final String TAG_STYLE = "style";
+ public static final String TAG_STYLING = "styling";
+ public static final String TAG_LAYOUT = "layout";
+ public static final String TAG_REGION = "region";
+ public static final String TAG_METADATA = "metadata";
+ public static final String TAG_SMPTE_IMAGE = "smpte:image";
+ public static final String TAG_SMPTE_DATA = "smpte:data";
+ public static final String TAG_SMPTE_INFORMATION = "smpte:information";
+ public static final String PCDATA = "#pcdata";
+ public static final String ATTR_BEGIN = "begin";
+ public static final String ATTR_DURATION = "dur";
+ public static final String ATTR_END = "end";
+ public static final long INVALID_TIMESTAMP = Long.MAX_VALUE;
+
+ /**
+ * Time expression RE according to the spec:
+ * http://www.w3.org/TR/ttaf1-dfxp/#timing-value-timeExpression
+ */
+ private static final Pattern CLOCK_TIME = Pattern.compile(
+ "^([0-9][0-9]+):([0-9][0-9]):([0-9][0-9])"
+ + "(?:(\\.[0-9]+)|:([0-9][0-9])(?:\\.([0-9]+))?)?$");
+
+ private static final Pattern OFFSET_TIME = Pattern.compile(
+ "^([0-9]+(?:\\.[0-9]+)?)(h|m|s|ms|f|t)$");
+
+ private TtmlUtils() {
+ }
+
+ /**
+ * Parses the given time expression and returns a timestamp in millisecond.
+ * <p>
+ * For the format of the time expression, please refer <a href=
+ * "http://www.w3.org/TR/ttaf1-dfxp/#timing-value-timeExpression">timeExpression</a>
+ *
+ * @param time A string which includes time expression.
+ * @param frameRate the framerate of the stream.
+ * @param subframeRate the sub-framerate of the stream
+ * @param tickRate the tick rate of the stream.
+ * @return the parsed timestamp in micro-second.
+ * @throws NumberFormatException if the given string does not match to the
+ * format.
+ */
+ public static long parseTimeExpression(String time, int frameRate, int subframeRate,
+ int tickRate) throws NumberFormatException {
+ Matcher matcher = CLOCK_TIME.matcher(time);
+ if (matcher.matches()) {
+ String hours = matcher.group(1);
+ double durationSeconds = Long.parseLong(hours) * 3600;
+ String minutes = matcher.group(2);
+ durationSeconds += Long.parseLong(minutes) * 60;
+ String seconds = matcher.group(3);
+ durationSeconds += Long.parseLong(seconds);
+ String fraction = matcher.group(4);
+ durationSeconds += (fraction != null) ? Double.parseDouble(fraction) : 0;
+ String frames = matcher.group(5);
+ durationSeconds += (frames != null) ? ((double)Long.parseLong(frames)) / frameRate : 0;
+ String subframes = matcher.group(6);
+ durationSeconds += (subframes != null) ? ((double)Long.parseLong(subframes))
+ / subframeRate / frameRate
+ : 0;
+ return (long)(durationSeconds * 1000);
+ }
+ matcher = OFFSET_TIME.matcher(time);
+ if (matcher.matches()) {
+ String timeValue = matcher.group(1);
+ double value = Double.parseDouble(timeValue);
+ String unit = matcher.group(2);
+ if (unit.equals("h")) {
+ value *= 3600L * 1000000L;
+ } else if (unit.equals("m")) {
+ value *= 60 * 1000000;
+ } else if (unit.equals("s")) {
+ value *= 1000000;
+ } else if (unit.equals("ms")) {
+ value *= 1000;
+ } else if (unit.equals("f")) {
+ value = value / frameRate * 1000000;
+ } else if (unit.equals("t")) {
+ value = value / tickRate * 1000000;
+ }
+ return (long)value;
+ }
+ throw new NumberFormatException("Malformed time expression : " + time);
+ }
+
+ /**
+ * Applies <a href
+ * src="http://www.w3.org/TR/ttaf1-dfxp/#content-attribute-space">the
+ * default space policy</a> to the given string.
+ *
+ * @param in A string to apply the policy.
+ */
+ public static String applyDefaultSpacePolicy(String in) {
+ return applySpacePolicy(in, true);
+ }
+
+ /**
+ * Applies the space policy to the given string. This applies <a href
+ * src="http://www.w3.org/TR/ttaf1-dfxp/#content-attribute-space">the
+ * default space policy</a> with linefeed-treatment as treat-as-space
+ * or preserve.
+ *
+ * @param in A string to apply the policy.
+ * @param treatLfAsSpace Whether convert line feeds to spaces or not.
+ */
+ public static String applySpacePolicy(String in, boolean treatLfAsSpace) {
+ // Removes CR followed by LF. ref:
+ // http://www.w3.org/TR/xml/#sec-line-ends
+ String crRemoved = in.replaceAll("\r\n", "\n");
+ // Apply suppress-at-line-break="auto" and
+ // white-space-treatment="ignore-if-surrounding-linefeed"
+ String spacesNeighboringLfRemoved = crRemoved.replaceAll(" *\n *", "\n");
+ // Apply linefeed-treatment="treat-as-space"
+ String lfToSpace = treatLfAsSpace ? spacesNeighboringLfRemoved.replaceAll("\n", " ")
+ : spacesNeighboringLfRemoved;
+ // Apply white-space-collapse="true"
+ String spacesCollapsed = lfToSpace.replaceAll("[ \t\\x0B\f\r]+", " ");
+ return spacesCollapsed;
+ }
+
+ /**
+ * Returns the timed text for the given time period.
+ *
+ * @param root The root node of the TTML document.
+ * @param startUs The start time of the time period in microsecond.
+ * @param endUs The end time of the time period in microsecond.
+ */
+ public static String extractText(TtmlNode root, long startUs, long endUs) {
+ StringBuilder text = new StringBuilder();
+ extractText(root, startUs, endUs, text, false);
+ return text.toString().replaceAll("\n$", "");
+ }
+
+ private static void extractText(TtmlNode node, long startUs, long endUs, StringBuilder out,
+ boolean inPTag) {
+ if (node.mName.equals(TtmlUtils.PCDATA) && inPTag) {
+ out.append(node.mText);
+ } else if (node.mName.equals(TtmlUtils.TAG_BR) && inPTag) {
+ out.append("\n");
+ } else if (node.mName.equals(TtmlUtils.TAG_METADATA)) {
+ // do nothing.
+ } else if (node.isActive(startUs, endUs)) {
+ boolean pTag = node.mName.equals(TtmlUtils.TAG_P);
+ int length = out.length();
+ for (int i = 0; i < node.mChildren.size(); ++i) {
+ extractText(node.mChildren.get(i), startUs, endUs, out, pTag || inPTag);
+ }
+ if (pTag && length != out.length()) {
+ out.append("\n");
+ }
+ }
+ }
+
+ /**
+ * Returns a TTML fragment string for the given time period.
+ *
+ * @param root The root node of the TTML document.
+ * @param startUs The start time of the time period in microsecond.
+ * @param endUs The end time of the time period in microsecond.
+ */
+ public static String extractTtmlFragment(TtmlNode root, long startUs, long endUs) {
+ StringBuilder fragment = new StringBuilder();
+ extractTtmlFragment(root, startUs, endUs, fragment);
+ return fragment.toString();
+ }
+
+ private static void extractTtmlFragment(TtmlNode node, long startUs, long endUs,
+ StringBuilder out) {
+ if (node.mName.equals(TtmlUtils.PCDATA)) {
+ out.append(node.mText);
+ } else if (node.mName.equals(TtmlUtils.TAG_BR)) {
+ out.append("<br/>");
+ } else if (node.isActive(startUs, endUs)) {
+ out.append("<");
+ out.append(node.mName);
+ out.append(node.mAttributes);
+ out.append(">");
+ for (int i = 0; i < node.mChildren.size(); ++i) {
+ extractTtmlFragment(node.mChildren.get(i), startUs, endUs, out);
+ }
+ out.append("</");
+ out.append(node.mName);
+ out.append(">");
+ }
+ }
+}
+
+/**
+ * A container class which represents a cue in TTML.
+ * @hide
+ */
+class TtmlCue extends SubtitleTrack.Cue {
+ public String mText;
+ public String mTtmlFragment;
+
+ public TtmlCue(long startTimeMs, long endTimeMs, String text, String ttmlFragment) {
+ this.mStartTimeMs = startTimeMs;
+ this.mEndTimeMs = endTimeMs;
+ this.mText = text;
+ this.mTtmlFragment = ttmlFragment;
+ }
+}
+
+/**
+ * A container class which represents a node in TTML.
+ *
+ * @hide
+ */
+class TtmlNode {
+ public final String mName;
+ public final String mAttributes;
+ public final TtmlNode mParent;
+ public final String mText;
+ public final List<TtmlNode> mChildren = new ArrayList<TtmlNode>();
+ public final long mRunId;
+ public final long mStartTimeMs;
+ public final long mEndTimeMs;
+
+ public TtmlNode(String name, String attributes, String text, long startTimeMs, long endTimeMs,
+ TtmlNode parent, long runId) {
+ this.mName = name;
+ this.mAttributes = attributes;
+ this.mText = text;
+ this.mStartTimeMs = startTimeMs;
+ this.mEndTimeMs = endTimeMs;
+ this.mParent = parent;
+ this.mRunId = runId;
+ }
+
+ /**
+ * Check if this node is active in the given time range.
+ *
+ * @param startTimeMs The start time of the range to check in microsecond.
+ * @param endTimeMs The end time of the range to check in microsecond.
+ * @return return true if the given range overlaps the time range of this
+ * node.
+ */
+ public boolean isActive(long startTimeMs, long endTimeMs) {
+ return this.mEndTimeMs > startTimeMs && this.mStartTimeMs < endTimeMs;
+ }
+}
+
+/**
+ * A simple TTML parser (http://www.w3.org/TR/ttaf1-dfxp/) which supports DFXP
+ * presentation profile.
+ * <p>
+ * Supported features in this parser are:
+ * <ul>
+ * <li>content
+ * <li>core
+ * <li>presentation
+ * <li>profile
+ * <li>structure
+ * <li>time-offset
+ * <li>timing
+ * <li>tickRate
+ * <li>time-clock-with-frames
+ * <li>time-clock
+ * <li>time-offset-with-frames
+ * <li>time-offset-with-ticks
+ * </ul>
+ * </p>
+ *
+ * @hide
+ */
+class TtmlParser {
+ static final String TAG = "TtmlParser";
+
+ // TODO: read and apply the following attributes if specified.
+ private static final int DEFAULT_FRAMERATE = 30;
+ private static final int DEFAULT_SUBFRAMERATE = 1;
+ private static final int DEFAULT_TICKRATE = 1;
+
+ private XmlPullParser mParser;
+ private final TtmlNodeListener mListener;
+ private long mCurrentRunId;
+
+ public TtmlParser(TtmlNodeListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Parse TTML data. Once this is called, all the previous data are
+ * reset and it starts parsing for the given text.
+ *
+ * @param ttmlText TTML text to parse.
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ public void parse(String ttmlText, long runId) throws XmlPullParserException, IOException {
+ mParser = null;
+ mCurrentRunId = runId;
+ loadParser(ttmlText);
+ parseTtml();
+ }
+
+ private void loadParser(String ttmlFragment) throws XmlPullParserException {
+ XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+ factory.setNamespaceAware(false);
+ mParser = factory.newPullParser();
+ StringReader in = new StringReader(ttmlFragment);
+ mParser.setInput(in);
+ }
+
+ private void extractAttribute(XmlPullParser parser, int i, StringBuilder out) {
+ out.append(" ");
+ out.append(parser.getAttributeName(i));
+ out.append("=\"");
+ out.append(parser.getAttributeValue(i));
+ out.append("\"");
+ }
+
+ private void parseTtml() throws XmlPullParserException, IOException {
+ LinkedList<TtmlNode> nodeStack = new LinkedList<TtmlNode>();
+ int depthInUnsupportedTag = 0;
+ boolean active = true;
+ while (!isEndOfDoc()) {
+ int eventType = mParser.getEventType();
+ TtmlNode parent = nodeStack.peekLast();
+ if (active) {
+ if (eventType == XmlPullParser.START_TAG) {
+ if (!isSupportedTag(mParser.getName())) {
+ Log.w(TAG, "Unsupported tag " + mParser.getName() + " is ignored.");
+ depthInUnsupportedTag++;
+ active = false;
+ } else {
+ TtmlNode node = parseNode(parent);
+ nodeStack.addLast(node);
+ if (parent != null) {
+ parent.mChildren.add(node);
+ }
+ }
+ } else if (eventType == XmlPullParser.TEXT) {
+ String text = TtmlUtils.applyDefaultSpacePolicy(mParser.getText());
+ if (!TextUtils.isEmpty(text)) {
+ parent.mChildren.add(new TtmlNode(
+ TtmlUtils.PCDATA, "", text, 0, TtmlUtils.INVALID_TIMESTAMP,
+ parent, mCurrentRunId));
+
+ }
+ } else if (eventType == XmlPullParser.END_TAG) {
+ if (mParser.getName().equals(TtmlUtils.TAG_P)) {
+ mListener.onTtmlNodeParsed(nodeStack.getLast());
+ } else if (mParser.getName().equals(TtmlUtils.TAG_TT)) {
+ mListener.onRootNodeParsed(nodeStack.getLast());
+ }
+ nodeStack.removeLast();
+ }
+ } else {
+ if (eventType == XmlPullParser.START_TAG) {
+ depthInUnsupportedTag++;
+ } else if (eventType == XmlPullParser.END_TAG) {
+ depthInUnsupportedTag--;
+ if (depthInUnsupportedTag == 0) {
+ active = true;
+ }
+ }
+ }
+ mParser.next();
+ }
+ }
+
+ private TtmlNode parseNode(TtmlNode parent) throws XmlPullParserException, IOException {
+ int eventType = mParser.getEventType();
+ if (!(eventType == XmlPullParser.START_TAG)) {
+ return null;
+ }
+ StringBuilder attrStr = new StringBuilder();
+ long start = 0;
+ long end = TtmlUtils.INVALID_TIMESTAMP;
+ long dur = 0;
+ for (int i = 0; i < mParser.getAttributeCount(); ++i) {
+ String attr = mParser.getAttributeName(i);
+ String value = mParser.getAttributeValue(i);
+ // TODO: check if it's safe to ignore the namespace of attributes as follows.
+ attr = attr.replaceFirst("^.*:", "");
+ if (attr.equals(TtmlUtils.ATTR_BEGIN)) {
+ start = TtmlUtils.parseTimeExpression(value, DEFAULT_FRAMERATE,
+ DEFAULT_SUBFRAMERATE, DEFAULT_TICKRATE);
+ } else if (attr.equals(TtmlUtils.ATTR_END)) {
+ end = TtmlUtils.parseTimeExpression(value, DEFAULT_FRAMERATE, DEFAULT_SUBFRAMERATE,
+ DEFAULT_TICKRATE);
+ } else if (attr.equals(TtmlUtils.ATTR_DURATION)) {
+ dur = TtmlUtils.parseTimeExpression(value, DEFAULT_FRAMERATE, DEFAULT_SUBFRAMERATE,
+ DEFAULT_TICKRATE);
+ } else {
+ extractAttribute(mParser, i, attrStr);
+ }
+ }
+ if (parent != null) {
+ start += parent.mStartTimeMs;
+ if (end != TtmlUtils.INVALID_TIMESTAMP) {
+ end += parent.mStartTimeMs;
+ }
+ }
+ if (dur > 0) {
+ if (end != TtmlUtils.INVALID_TIMESTAMP) {
+ Log.e(TAG, "'dur' and 'end' attributes are defined at the same time." +
+ "'end' value is ignored.");
+ }
+ end = start + dur;
+ }
+ if (parent != null) {
+ // If the end time remains unspecified, then the end point is
+ // interpreted as the end point of the external time interval.
+ if (end == TtmlUtils.INVALID_TIMESTAMP &&
+ parent.mEndTimeMs != TtmlUtils.INVALID_TIMESTAMP &&
+ end > parent.mEndTimeMs) {
+ end = parent.mEndTimeMs;
+ }
+ }
+ TtmlNode node = new TtmlNode(mParser.getName(), attrStr.toString(), null, start, end,
+ parent, mCurrentRunId);
+ return node;
+ }
+
+ private boolean isEndOfDoc() throws XmlPullParserException {
+ return (mParser.getEventType() == XmlPullParser.END_DOCUMENT);
+ }
+
+ private static boolean isSupportedTag(String tag) {
+ if (tag.equals(TtmlUtils.TAG_TT) || tag.equals(TtmlUtils.TAG_HEAD) ||
+ tag.equals(TtmlUtils.TAG_BODY) || tag.equals(TtmlUtils.TAG_DIV) ||
+ tag.equals(TtmlUtils.TAG_P) || tag.equals(TtmlUtils.TAG_SPAN) ||
+ tag.equals(TtmlUtils.TAG_BR) || tag.equals(TtmlUtils.TAG_STYLE) ||
+ tag.equals(TtmlUtils.TAG_STYLING) || tag.equals(TtmlUtils.TAG_LAYOUT) ||
+ tag.equals(TtmlUtils.TAG_REGION) || tag.equals(TtmlUtils.TAG_METADATA) ||
+ tag.equals(TtmlUtils.TAG_SMPTE_IMAGE) || tag.equals(TtmlUtils.TAG_SMPTE_DATA) ||
+ tag.equals(TtmlUtils.TAG_SMPTE_INFORMATION)) {
+ return true;
+ }
+ return false;
+ }
+}
+
+/** @hide */
+interface TtmlNodeListener {
+ void onTtmlNodeParsed(TtmlNode node);
+ void onRootNodeParsed(TtmlNode node);
+}
+
+/** @hide */
+class TtmlTrack extends SubtitleTrack implements TtmlNodeListener {
+ private static final String TAG = "TtmlTrack";
+
+ private final TtmlParser mParser = new TtmlParser(this);
+ private final TtmlRenderingWidget mRenderingWidget;
+ private String mParsingData;
+ private Long mCurrentRunID;
+
+ private final LinkedList<TtmlNode> mTtmlNodes;
+ private final TreeSet<Long> mTimeEvents;
+ private TtmlNode mRootNode;
+
+ TtmlTrack(TtmlRenderingWidget renderingWidget, MediaFormat format) {
+ super(format);
+
+ mTtmlNodes = new LinkedList<TtmlNode>();
+ mTimeEvents = new TreeSet<Long>();
+ mRenderingWidget = renderingWidget;
+ mParsingData = "";
+ }
+
+ @Override
+ public TtmlRenderingWidget getRenderingWidget() {
+ return mRenderingWidget;
+ }
+
+ @Override
+ public void onData(String data, boolean eos, long runID) {
+ // implement intermixing restriction for TTML.
+ synchronized(mParser) {
+ if (mCurrentRunID != null && runID != mCurrentRunID) {
+ throw new IllegalStateException(
+ "Run #" + mCurrentRunID +
+ " in progress. Cannot process run #" + runID);
+ }
+ mCurrentRunID = runID;
+ mParsingData += data;
+ if (eos) {
+ try {
+ mParser.parse(mParsingData, mCurrentRunID);
+ } catch (XmlPullParserException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ finishedRun(runID);
+ mParsingData = "";
+ mCurrentRunID = null;
+ }
+ }
+ }
+
+ @Override
+ public void onTtmlNodeParsed(TtmlNode node) {
+ mTtmlNodes.addLast(node);
+ addTimeEvents(node);
+ }
+
+ @Override
+ public void onRootNodeParsed(TtmlNode node) {
+ mRootNode = node;
+ TtmlCue cue = null;
+ while ((cue = getNextResult()) != null) {
+ addCue(cue);
+ }
+ mRootNode = null;
+ mTtmlNodes.clear();
+ mTimeEvents.clear();
+ }
+
+ @Override
+ public void updateView(Vector<SubtitleTrack.Cue> activeCues) {
+ if (!mVisible) {
+ // don't keep the state if we are not visible
+ return;
+ }
+
+ if (DEBUG && mTimeProvider != null) {
+ try {
+ Log.d(TAG, "at " +
+ (mTimeProvider.getCurrentTimeUs(false, true) / 1000) +
+ " ms the active cues are:");
+ } catch (IllegalStateException e) {
+ Log.d(TAG, "at (illegal state) the active cues are:");
+ }
+ }
+
+ mRenderingWidget.setActiveCues(activeCues);
+ }
+
+ /**
+ * Returns a {@link TtmlCue} in the presentation time order.
+ * {@code null} is returned if there is no more timed text to show.
+ */
+ public TtmlCue getNextResult() {
+ while (mTimeEvents.size() >= 2) {
+ long start = mTimeEvents.pollFirst();
+ long end = mTimeEvents.first();
+ List<TtmlNode> activeCues = getActiveNodes(start, end);
+ if (!activeCues.isEmpty()) {
+ return new TtmlCue(start, end,
+ TtmlUtils.applySpacePolicy(TtmlUtils.extractText(
+ mRootNode, start, end), false),
+ TtmlUtils.extractTtmlFragment(mRootNode, start, end));
+ }
+ }
+ return null;
+ }
+
+ private void addTimeEvents(TtmlNode node) {
+ mTimeEvents.add(node.mStartTimeMs);
+ mTimeEvents.add(node.mEndTimeMs);
+ for (int i = 0; i < node.mChildren.size(); ++i) {
+ addTimeEvents(node.mChildren.get(i));
+ }
+ }
+
+ private List<TtmlNode> getActiveNodes(long startTimeUs, long endTimeUs) {
+ List<TtmlNode> activeNodes = new ArrayList<TtmlNode>();
+ for (int i = 0; i < mTtmlNodes.size(); ++i) {
+ TtmlNode node = mTtmlNodes.get(i);
+ if (node.isActive(startTimeUs, endTimeUs)) {
+ activeNodes.add(node);
+ }
+ }
+ return activeNodes;
+ }
+}
+
+/**
+ * Widget capable of rendering TTML captions.
+ *
+ * @hide
+ */
+class TtmlRenderingWidget extends LinearLayout implements SubtitleTrack.RenderingWidget {
+
+ /** Callback for rendering changes. */
+ private OnChangedListener mListener;
+ private final TextView mTextView;
+
+ public TtmlRenderingWidget(Context context) {
+ this(context, null);
+ }
+
+ public TtmlRenderingWidget(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public TtmlRenderingWidget(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public TtmlRenderingWidget(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ // Cannot render text over video when layer type is hardware.
+ setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+
+ CaptioningManager captionManager = (CaptioningManager) context.getSystemService(
+ Context.CAPTIONING_SERVICE);
+ mTextView = new TextView(context);
+ mTextView.setTextColor(captionManager.getUserStyle().foregroundColor);
+ addView(mTextView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ mTextView.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
+ }
+
+ @Override
+ public void setOnChangedListener(OnChangedListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void setSize(int width, int height) {
+ final int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
+ final int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+
+ measure(widthSpec, heightSpec);
+ layout(0, 0, width, height);
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ if (visible) {
+ setVisibility(View.VISIBLE);
+ } else {
+ setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ }
+
+ public void setActiveCues(Vector<SubtitleTrack.Cue> activeCues) {
+ final int count = activeCues.size();
+ String subtitleText = "";
+ for (int i = 0; i < count; i++) {
+ TtmlCue cue = (TtmlCue) activeCues.get(i);
+ subtitleText += cue.mText + "\n";
+ }
+ mTextView.setText(subtitleText);
+
+ if (mListener != null) {
+ mListener.onChanged(this);
+ }
+ }
+}
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index 3ff07d9..096550f 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -40,6 +40,7 @@ interface ISession {
boolean setRoute(in RouteInfo route);
void setRouteOptions(in List<RouteOptions> options);
void connectToRoute(in RouteInfo route, in RouteOptions options);
+ void disconnectFromRoute(in RouteInfo route);
void sendRouteCommand(in RouteCommand event, in ResultReceiver cb);
// These commands are for the TransportPerformer
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index f04cbcc..1552513 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -31,6 +31,7 @@ oneway interface ISessionCallback {
void onMediaButton(in Intent mediaButtonIntent);
void onRequestRouteChange(in RouteInfo route);
void onRouteConnected(in RouteInfo route, in RouteOptions options);
+ void onRouteDisconnected(in RouteInfo route, int reason);
void onRouteStateChange(int state);
void onRouteEvent(in RouteEvent event);
diff --git a/media/java/android/media/session/Session.java b/media/java/android/media/session/Session.java
index 194679e7..2ffced6 100644
--- a/media/java/android/media/session/Session.java
+++ b/media/java/android/media/session/Session.java
@@ -86,10 +86,39 @@ public final class Session {
*/
public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 1 << 16;
+ /**
+ * Indicates the session was disconnected because the user that the session
+ * belonged to is stopping.
+ */
+ public static final int DISCONNECT_REASON_USER_STOPPING = 1;
+
+ /**
+ * Indicates the session was disconnected because the provider disconnected
+ * the route.
+ */
+ public static final int DISCONNECT_REASON_PROVIDER_DISCONNECTED = 2;
+
+ /**
+ * Indicates the session was disconnected because the route has changed.
+ */
+ public static final int DISCONNECT_REASON_ROUTE_CHANGED = 3;
+
+ /**
+ * Indicates the session was disconnected because the session owner
+ * requested it disconnect.
+ */
+ public static final int DISCONNECT_REASON_SESSION_DISCONNECTED = 4;
+
+ /**
+ * Indicates the session was disconnected because it was destroyed.
+ */
+ public static final int DISCONNECT_REASON_SESSION_DESTROYED = 5;
+
private static final int MSG_MEDIA_BUTTON = 1;
private static final int MSG_COMMAND = 2;
private static final int MSG_ROUTE_CHANGE = 3;
private static final int MSG_ROUTE_CONNECTED = 4;
+ private static final int MSG_ROUTE_DISCONNECTED = 5;
private static final String KEY_COMMAND = "command";
private static final String KEY_EXTRAS = "extras";
@@ -302,11 +331,15 @@ public final class Session {
/**
* Disconnect from the current route. After calling you will be switched
* back to the default route.
- *
- * @param route The route to disconnect from.
*/
- public void disconnect(RouteInfo route) {
- // TODO
+ public void disconnect() {
+ if (mRoute != null) {
+ try {
+ mBinder.disconnectFromRoute(mRoute.getRouteInfo());
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error disconnecting from route");
+ }
+ }
}
/**
@@ -406,6 +439,16 @@ public final class Session {
}
}
+ private void postRouteDisconnected(RouteInfo route, int reason) {
+ synchronized (mLock) {
+ if (mRoute != null && TextUtils.equals(mRoute.getRouteInfo().getId(), route.getId())) {
+ for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+ mCallbacks.get(i).post(MSG_ROUTE_DISCONNECTED, mRoute, reason);
+ }
+ }
+ }
+ }
+
/**
* Receives commands or updates from controllers and routes. An app can
* specify what commands and buttons it supports by setting them on the
@@ -467,6 +510,11 @@ public final class Session {
* <p>
* Valid reasons are:
* <ul>
+ * <li>{@link #DISCONNECT_REASON_USER_STOPPING}</li>
+ * <li>{@link #DISCONNECT_REASON_PROVIDER_DISCONNECTED}</li>
+ * <li>{@link #DISCONNECT_REASON_ROUTE_CHANGED}</li>
+ * <li>{@link #DISCONNECT_REASON_SESSION_DISCONNECTED}</li>
+ * <li>{@link #DISCONNECT_REASON_SESSION_DESTROYED}</li>
* </ul>
*
* @param route The route that disconnected
@@ -520,6 +568,14 @@ public final class Session {
}
@Override
+ public void onRouteDisconnected(RouteInfo route, int reason) {
+ Session session = mMediaSession.get();
+ if (session != null) {
+ session.postRouteDisconnected(route, reason);
+ }
+ }
+
+ @Override
public void onPlay() throws RemoteException {
Session session = mMediaSession.get();
if (session != null) {
@@ -668,6 +724,9 @@ public final class Session {
case MSG_ROUTE_CONNECTED:
mCallback.onRouteConnected((Route) msg.obj);
break;
+ case MSG_ROUTE_DISCONNECTED:
+ mCallback.onRouteDisconnected((Route) msg.obj, msg.arg1);
+ break;
}
}
}
@@ -675,6 +734,10 @@ public final class Session {
public void post(int what, Object obj) {
obtainMessage(what, obj).sendToTarget();
}
+
+ public void post(int what, Object obj, int arg1) {
+ obtainMessage(what, arg1, 0, obj).sendToTarget();
+ }
}
private static final class Command {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index b28733a..5ab586f 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -23,19 +23,21 @@ import android.graphics.ImageFormat;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.ColorSpaceTransform;
import android.hardware.camera2.Face;
import android.hardware.camera2.MeteringRectangle;
import android.hardware.camera2.Rational;
-import android.hardware.camera2.ReprocessFormatsMap;
import android.hardware.camera2.RggbChannelVector;
import android.hardware.camera2.Size;
-import android.hardware.camera2.StreamConfiguration;
-import android.hardware.camera2.StreamConfigurationDuration;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
+import android.hardware.camera2.params.ReprocessFormatsMap;
+import android.hardware.camera2.params.StreamConfiguration;
+import android.hardware.camera2.params.StreamConfigurationDuration;
+import android.hardware.camera2.params.StreamConfigurationMap;
import android.hardware.camera2.utils.TypeReference;
import static android.hardware.camera2.impl.CameraMetadataNative.*;
@@ -72,6 +74,9 @@ public class CameraMetadataTest extends junit.framework.TestCase {
static final int ANDROID_CONTROL_AE_ANTIBANDING_MODE = ANDROID_CONTROL_START;
static final int ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION = ANDROID_CONTROL_START + 1;
+ // From graphics.h
+ private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;
+
@Override
public void setUp() {
mMetadata = new CameraMetadataNative();
@@ -293,6 +298,28 @@ public class CameraMetadataTest extends junit.framework.TestCase {
}
}
+ private static <T, T2> void assertArrayContains(T needle, T2 array) {
+ if (!array.getClass().isArray()) {
+ throw new IllegalArgumentException("actual must be array");
+ }
+
+ int len = Array.getLength(array);
+ for (int i = 0; i < len; ++i) {
+
+ Object actualElement = Array.get(array, i);
+
+ if (needle.equals(actualElement)) {
+ return;
+ }
+ }
+
+ fail(String.format(
+ "could not find element in array (needle %s). "
+ + "Array was: %s.",
+ needle,
+ formatArray(array, len)));
+ }
+
private <T> void checkKeyGetAndSet(String keyStr, TypeReference<T> typeToken, T expected,
boolean reuse) {
Key<T> key = new Key<T>(keyStr, typeToken);
@@ -804,18 +831,48 @@ public class CameraMetadataTest extends junit.framework.TestCase {
@SmallTest
public void testReadWriteReprocessFormatsMap() {
- final int RAW_OPAQUE = 0x24;
+ // final int RAW_OPAQUE = 0x24; // TODO: add RAW_OPAQUE to ImageFormat
final int RAW16 = ImageFormat.RAW_SENSOR;
final int YUV_420_888 = ImageFormat.YUV_420_888;
final int BLOB = 0x21;
+ // TODO: also test HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED as an output
int[] contents = new int[] {
- RAW_OPAQUE, 3, RAW16, YUV_420_888, BLOB,
+ YUV_420_888, 3, YUV_420_888, ImageFormat.NV21, BLOB,
RAW16, 2, YUV_420_888, BLOB,
+
};
// int32 x n
- checkKeyMarshal("android.scaler.availableInputOutputFormatsMap",
+ Key<ReprocessFormatsMap> key = new Key<ReprocessFormatsMap>(
+ "android.scaler.availableInputOutputFormatsMap", ReprocessFormatsMap.class);
+ mMetadata.writeValues(key.getTag(), toByteArray(contents));
+
+ ReprocessFormatsMap map = mMetadata.get(key);
+
+ /*
+ * Make sure the inputs/outputs were what we expected.
+ * - Use public image format constants here.
+ */
+
+ int[] expectedInputs = new int[] {
+ YUV_420_888, RAW16
+ };
+ assertArrayEquals(expectedInputs, map.getInputs());
+
+ int[] expectedYuvOutputs = new int[] {
+ YUV_420_888, ImageFormat.NV21, ImageFormat.JPEG,
+ };
+ assertArrayEquals(expectedYuvOutputs, map.getOutputs(ImageFormat.YUV_420_888));
+
+ int[] expectedRaw16Outputs = new int[] {
+ YUV_420_888, ImageFormat.JPEG,
+ };
+ assertArrayEquals(expectedRaw16Outputs, map.getOutputs(ImageFormat.RAW_SENSOR));
+
+ // Finally, do a round-trip check as a sanity
+ checkKeyMarshal(
+ "android.scaler.availableInputOutputFormatsMap",
new ReprocessFormatsMap(contents),
toByteArray(contents)
);
@@ -889,68 +946,6 @@ public class CameraMetadataTest extends junit.framework.TestCase {
expectedIntValues, availableFormatTag);
//
- // android.scaler.availableStreamConfigurations (int x n x 4 array)
- //
- final int OUTPUT = CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT;
- int[] availableStreamConfigs = new int[] {
- 0x20, 3280, 2464, OUTPUT, // RAW16
- 0x23, 3264, 2448, OUTPUT, // YCbCr_420_888
- 0x23, 3200, 2400, OUTPUT, // YCbCr_420_888
- 0x100, 3264, 2448, OUTPUT, // ImageFormat.JPEG
- 0x100, 3200, 2400, OUTPUT, // ImageFormat.JPEG
- 0x100, 2592, 1944, OUTPUT, // ImageFormat.JPEG
- 0x100, 2048, 1536, OUTPUT, // ImageFormat.JPEG
- 0x100, 1920, 1080, OUTPUT // ImageFormat.JPEG
- };
- int[] expectedAvailableStreamConfigs = new int[] {
- 0x20, 3280, 2464, OUTPUT, // RAW16
- 0x23, 3264, 2448, OUTPUT, // YCbCr_420_888
- 0x23, 3200, 2400, OUTPUT, // YCbCr_420_888
- 0x21, 3264, 2448, OUTPUT, // BLOB
- 0x21, 3200, 2400, OUTPUT, // BLOB
- 0x21, 2592, 1944, OUTPUT, // BLOB
- 0x21, 2048, 1536, OUTPUT, // BLOB
- 0x21, 1920, 1080, OUTPUT // BLOB
- };
- int availableStreamConfigTag =
- CameraMetadataNative.getTag("android.scaler.availableStreamConfigurations");
-
- Key<int[]> configKey = CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
- validateArrayMetadataReadWriteOverride(configKey, availableStreamConfigs,
- expectedAvailableStreamConfigs, availableStreamConfigTag);
-
- //
- // android.scaler.availableMinFrameDurations (int x n x 4 array)
-
- //
- long[] availableMinDurations = new long[] {
- 0x20, 3280, 2464, 33333336, // RAW16
- 0x23, 3264, 2448, 33333336, // YCbCr_420_888
- 0x23, 3200, 2400, 33333336, // YCbCr_420_888
- 0x100, 3264, 2448, 33333336, // ImageFormat.JPEG
- 0x100, 3200, 2400, 33333336, // ImageFormat.JPEG
- 0x100, 2592, 1944, 33333336, // ImageFormat.JPEG
- 0x100, 2048, 1536, 33333336, // ImageFormat.JPEG
- 0x100, 1920, 1080, 33333336 // ImageFormat.JPEG
- };
- long[] expectedAvailableMinDurations = new long[] {
- 0x20, 3280, 2464, 33333336, // RAW16
- 0x23, 3264, 2448, 33333336, // YCbCr_420_888
- 0x23, 3200, 2400, 33333336, // YCbCr_420_888
- 0x21, 3264, 2448, 33333336, // BLOB
- 0x21, 3200, 2400, 33333336, // BLOB
- 0x21, 2592, 1944, 33333336, // BLOB
- 0x21, 2048, 1536, 33333336, // BLOB
- 0x21, 1920, 1080, 33333336 // BLOB
- };
- int availableMinDurationsTag =
- CameraMetadataNative.getTag("android.scaler.availableMinFrameDurations");
-
- Key<long[]> durationKey = CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
- validateArrayMetadataReadWriteOverride(durationKey, availableMinDurations,
- expectedAvailableMinDurations, availableMinDurationsTag);
-
- //
// android.statistics.faces (Face x n array)
//
int[] expectedFaceIds = new int[] {1, 2, 3, 4, 5};
@@ -1015,14 +1010,238 @@ public class CameraMetadataTest extends junit.framework.TestCase {
}
/**
+ * Set the raw native value of the available stream configurations; ensure that
+ * the read-out managed value is consistent with what we write in.
+ */
+ @SmallTest
+ public void testOverrideStreamConfigurationMap() {
+
+ /*
+ * First, write all the raw values:
+ * - availableStreamConfigurations
+ * - availableMinFrameDurations
+ * - availableStallDurations
+ *
+ * Then, read this out as a synthetic multi-key 'streamConfigurationMap'
+ *
+ * Finally, validate that the map was unmarshaled correctly
+ * and is converting the internal formats to public formats properly.
+ */
+
+ //
+ // android.scaler.availableStreamConfigurations (int x n x 4 array)
+ //
+ final int OUTPUT = 0;
+ final int INPUT = 1;
+ int[] rawAvailableStreamConfigs = new int[] {
+ 0x20, 3280, 2464, OUTPUT, // RAW16
+ 0x23, 3264, 2448, OUTPUT, // YCbCr_420_888
+ 0x23, 3200, 2400, OUTPUT, // YCbCr_420_888
+ 0x21, 3264, 2448, OUTPUT, // BLOB
+ 0x21, 3200, 2400, OUTPUT, // BLOB
+ 0x21, 2592, 1944, OUTPUT, // BLOB
+ 0x21, 2048, 1536, OUTPUT, // BLOB
+ 0x21, 1920, 1080, OUTPUT, // BLOB
+ 0x22, 640, 480, OUTPUT, // IMPLEMENTATION_DEFINED
+ 0x20, 320, 240, INPUT, // RAW16
+ };
+ Key<StreamConfiguration[]> configKey =
+ CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
+ mMetadata.writeValues(configKey.getTag(),
+ toByteArray(rawAvailableStreamConfigs));
+
+ //
+ // android.scaler.availableMinFrameDurations (int x n x 4 array)
+ //
+ long[] expectedAvailableMinDurations = new long[] {
+ 0x20, 3280, 2464, 33333331, // RAW16
+ 0x23, 3264, 2448, 33333332, // YCbCr_420_888
+ 0x23, 3200, 2400, 33333333, // YCbCr_420_888
+ 0x100, 3264, 2448, 33333334, // ImageFormat.JPEG
+ 0x100, 3200, 2400, 33333335, // ImageFormat.JPEG
+ 0x100, 2592, 1944, 33333336, // ImageFormat.JPEG
+ 0x100, 2048, 1536, 33333337, // ImageFormat.JPEG
+ 0x100, 1920, 1080, 33333338 // ImageFormat.JPEG
+ };
+ long[] rawAvailableMinDurations = new long[] {
+ 0x20, 3280, 2464, 33333331, // RAW16
+ 0x23, 3264, 2448, 33333332, // YCbCr_420_888
+ 0x23, 3200, 2400, 33333333, // YCbCr_420_888
+ 0x21, 3264, 2448, 33333334, // BLOB
+ 0x21, 3200, 2400, 33333335, // BLOB
+ 0x21, 2592, 1944, 33333336, // BLOB
+ 0x21, 2048, 1536, 33333337, // BLOB
+ 0x21, 1920, 1080, 33333338 // BLOB
+ };
+ Key<StreamConfigurationDuration[]> durationKey =
+ CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
+ mMetadata.writeValues(durationKey.getTag(),
+ toByteArray(rawAvailableMinDurations));
+
+ //
+ // android.scaler.availableStallDurations (int x n x 4 array)
+ //
+ long[] expectedAvailableStallDurations = new long[] {
+ 0x20, 3280, 2464, 0, // RAW16
+ 0x23, 3264, 2448, 0, // YCbCr_420_888
+ 0x23, 3200, 2400, 0, // YCbCr_420_888
+ 0x100, 3264, 2448, 33333334, // ImageFormat.JPEG
+ 0x100, 3200, 2400, 33333335, // ImageFormat.JPEG
+ 0x100, 2592, 1944, 33333336, // ImageFormat.JPEG
+ 0x100, 2048, 1536, 33333337, // ImageFormat.JPEG
+ 0x100, 1920, 1080, 33333338 // ImageFormat.JPEG
+ };
+ // Note: RAW16 and YUV_420_888 omitted intentionally; omitted values should default to 0
+ long[] rawAvailableStallDurations = new long[] {
+ 0x21, 3264, 2448, 33333334, // BLOB
+ 0x21, 3200, 2400, 33333335, // BLOB
+ 0x21, 2592, 1944, 33333336, // BLOB
+ 0x21, 2048, 1536, 33333337, // BLOB
+ 0x21, 1920, 1080, 33333338 // BLOB
+ };
+ Key<StreamConfigurationDuration[]> stallDurationKey =
+ CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS;
+ mMetadata.writeValues(stallDurationKey.getTag(),
+ toByteArray(rawAvailableStallDurations));
+
+ //
+ // android.scaler.streamConfigurationMap (synthetic as StreamConfigurationMap)
+ //
+ StreamConfigurationMap streamConfigMap = mMetadata.get(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+ // Inputs
+ checkStreamConfigurationMapByFormatSize(
+ streamConfigMap, ImageFormat.RAW_SENSOR, 320, 240, /*output*/false);
+
+ // Outputs
+ checkStreamConfigurationMapByFormatSize(
+ streamConfigMap, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 640, 480, /*output*/true);
+ checkStreamConfigurationMapByFormatSize(
+ streamConfigMap, ImageFormat.JPEG, 1920, 1080, /*output*/true);
+ checkStreamConfigurationMapByFormatSize(
+ streamConfigMap, ImageFormat.JPEG, 2048, 1536, /*output*/true);
+ checkStreamConfigurationMapByFormatSize(
+ streamConfigMap, ImageFormat.JPEG, 2592, 1944, /*output*/true);
+ checkStreamConfigurationMapByFormatSize(
+ streamConfigMap, ImageFormat.JPEG, 3200, 2400, /*output*/true);
+ checkStreamConfigurationMapByFormatSize(
+ streamConfigMap, ImageFormat.YUV_420_888, 3200, 2400, /*output*/true);
+ checkStreamConfigurationMapByFormatSize(
+ streamConfigMap, ImageFormat.YUV_420_888, 3264, 2448, /*output*/true);
+ checkStreamConfigurationMapByFormatSize(
+ streamConfigMap, ImageFormat.RAW_SENSOR, 3280, 2464, /*output*/true);
+
+ // Min Frame Durations
+
+ final int DURATION_TUPLE_SIZE = 4;
+ for (int i = 0; i < expectedAvailableMinDurations.length; i += DURATION_TUPLE_SIZE) {
+ checkStreamConfigurationMapDurationByFormatSize(
+ streamConfigMap,
+ (int)expectedAvailableMinDurations[i],
+ (int)expectedAvailableMinDurations[i+1],
+ (int)expectedAvailableMinDurations[i+2],
+ Duration.MinFrame,
+ expectedAvailableMinDurations[i+3]);
+ }
+
+ // Stall Frame Durations
+
+ for (int i = 0; i < expectedAvailableStallDurations.length; i += DURATION_TUPLE_SIZE) {
+ checkStreamConfigurationMapDurationByFormatSize(
+ streamConfigMap,
+ (int)expectedAvailableStallDurations[i],
+ (int)expectedAvailableStallDurations[i+1],
+ (int)expectedAvailableStallDurations[i+2],
+ Duration.Stall,
+ expectedAvailableStallDurations[i+3]);
+ }
+ }
+
+ private static void checkStreamConfigurationMapByFormatSize(StreamConfigurationMap configMap,
+ int format, int width, int height,
+ boolean output) {
+
+ /** arbitrary class for which StreamConfigurationMap#isOutputSupportedFor(Class) is true */
+ final Class<?> IMPLEMENTATION_DEFINED_OUTPUT_CLASS = SurfaceTexture.class;
+
+ android.util.Size[] sizes;
+ int[] formats;
+
+ if (output) {
+ if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ sizes = configMap.getOutputSizes(IMPLEMENTATION_DEFINED_OUTPUT_CLASS);
+ // in this case the 'is output format supported' is vacuously true
+ formats = new int[] { HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED };
+ } else {
+ sizes = configMap.getOutputSizes(format);
+ formats = configMap.getOutputFormats();
+ assertTrue("Format must be supported by stream configuration map",
+ configMap.isOutputSupportedFor(format));
+ }
+ } else {
+ // NOTE: No function to do input sizes from IMPL_DEFINED, so it would just fail for that
+ sizes = configMap.getInputSizes(format);
+ formats = configMap.getInputFormats();
+ }
+
+ android.util.Size expectedSize = new android.util.Size(width, height);
+
+ assertArrayContains(format, formats);
+ assertArrayContains(expectedSize, sizes);
+ }
+
+ private enum Duration {
+ MinFrame,
+ Stall
+ }
+
+ private static void checkStreamConfigurationMapDurationByFormatSize(
+ StreamConfigurationMap configMap,
+ int format, int width, int height, Duration durationKind, long expectedDuration) {
+
+ /** arbitrary class for which StreamConfigurationMap#isOutputSupportedFor(Class) is true */
+ final Class<?> IMPLEMENTATION_DEFINED_OUTPUT_CLASS = SurfaceTexture.class;
+
+ long actualDuration;
+
+ android.util.Size size = new android.util.Size(width, height);
+ switch (durationKind) {
+ case MinFrame:
+ if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ actualDuration = configMap.getOutputMinFrameDuration(
+ IMPLEMENTATION_DEFINED_OUTPUT_CLASS, size);
+ } else {
+ actualDuration = configMap.getOutputMinFrameDuration(format, size);
+ }
+
+ break;
+ case Stall:
+ if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ actualDuration = configMap.getOutputStallDuration(
+ IMPLEMENTATION_DEFINED_OUTPUT_CLASS, size);
+ } else {
+ actualDuration = configMap.getOutputStallDuration(format, size);
+ }
+
+ break;
+ default:
+ throw new AssertionError();
+ }
+
+ assertEquals("Expected " + durationKind + " to match actual value", expectedDuration,
+ actualDuration);
+ }
+
+ /**
* Validate metadata array tag read/write override.
*
* <p>Only support long and int array for now, can be easily extend to support other
* primitive arrays.</p>
*/
- private <T> void validateArrayMetadataReadWriteOverride(Key<T> key, T writeValues,
- T readValues, int tag) {
- Class<?> type = writeValues.getClass();
+ private <T> void validateArrayMetadataReadWriteOverride(Key<T> key, T expectedWriteValues,
+ T expectedReadValues, int tag) {
+ Class<?> type = expectedWriteValues.getClass();
if (!type.isArray()) {
throw new IllegalArgumentException("This function expects an key with array type");
} else if (type != int[].class && type != long[].class) {
@@ -1030,13 +1249,13 @@ public class CameraMetadataTest extends junit.framework.TestCase {
}
// Write
- mMetadata.set(key, writeValues);
+ mMetadata.set(key, expectedWriteValues);
byte[] readOutValues = mMetadata.readValues(tag);
ByteBuffer bf = ByteBuffer.wrap(readOutValues).order(ByteOrder.nativeOrder());
- int readValuesLength = Array.getLength(readValues);
+ int readValuesLength = Array.getLength(expectedReadValues);
int readValuesNumBytes = readValuesLength * 4;
if (type == long[].class) {
readValuesNumBytes = readValuesLength * 8;
@@ -1045,9 +1264,9 @@ public class CameraMetadataTest extends junit.framework.TestCase {
assertEquals(readValuesNumBytes, readOutValues.length);
for (int i = 0; i < readValuesLength; ++i) {
if (type == int[].class) {
- assertEquals(Array.getInt(readValues, i), bf.getInt());
+ assertEquals(Array.getInt(expectedReadValues, i), bf.getInt());
} else if (type == long[].class) {
- assertEquals(Array.getLong(readValues, i), bf.getLong());
+ assertEquals(Array.getLong(expectedReadValues, i), bf.getLong());
}
}
@@ -1057,16 +1276,16 @@ public class CameraMetadataTest extends junit.framework.TestCase {
ByteBuffer.wrap(readOutValuesAsByteArray).order(ByteOrder.nativeOrder());
for (int i = 0; i < readValuesLength; ++i) {
if (type == int[].class) {
- readOutValuesByteBuffer.putInt(Array.getInt(readValues, i));
+ readOutValuesByteBuffer.putInt(Array.getInt(expectedReadValues, i));
} else if (type == long[].class) {
- readOutValuesByteBuffer.putLong(Array.getLong(readValues, i));
+ readOutValuesByteBuffer.putLong(Array.getLong(expectedReadValues, i));
}
}
mMetadata.writeValues(tag, readOutValuesAsByteArray);
T result = mMetadata.get(key);
assertNotNull(key.getName() + " result shouldn't be null", result);
- assertArrayEquals(writeValues, result);
+ assertArrayEquals(expectedWriteValues, result);
}
// TODO: move somewhere else
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_location_off.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_location_off.png
deleted file mode 100644
index 189f27b..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_location_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_location_on.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_location_on.png
deleted file mode 100644
index b03d30c..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_location_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_location_off.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_location_off.png
deleted file mode 100644
index b692107..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_location_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_location_on.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_location_on.png
deleted file mode 100644
index 867c57d..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_location_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_off.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_off.png
deleted file mode 100644
index 7ce8f83..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_on.png
deleted file mode 100644
index 6300bdc..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_off.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_off.png
deleted file mode 100644
index c14c1bb..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_on.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_on.png
deleted file mode 100644
index d6d4c70..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_location_24_01.xml b/packages/SystemUI/res/drawable/ic_location_24_01.xml
new file mode 100644
index 0000000..ff37d9a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_01.xml
@@ -0,0 +1,28 @@
+<!--
+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="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M12.0,2.0C8.13,2.0 5.0,5.13 5.0,9.0c0.0,5.25 7.0,13.0 7.0,13.0s7.0,-7.75 7.0,-13.0C19.0,5.13 15.87,2.0 12.0,2.0zM12.0,11.5c-1.38,0.0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5c1.38,0.0 2.5,1.12 2.5,2.5S13.38,11.5 12.0,11.5z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_02.xml b/packages/SystemUI/res/drawable/ic_location_24_02.xml
new file mode 100644
index 0000000..bb4465f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_02.xml
@@ -0,0 +1,28 @@
+<!--
+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="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M12.0,4.0c-3.48,0.0 -6.3,2.82 -6.3,6.3C5.7,15.02 12.0,22.0 12.0,22.0s6.3,-6.98 6.3,-11.7C18.3,6.82 15.48,4.0 12.0,4.0zM12.0,12.55c-1.24,0.0 -2.25,-1.01 -2.25,-2.25S10.76,8.05 12.0,8.05c1.24,0.0 2.25,1.01 2.25,2.25S13.24,12.55 12.0,12.55z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_03.xml b/packages/SystemUI/res/drawable/ic_location_24_03.xml
new file mode 100644
index 0000000..956a8c3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_03.xml
@@ -0,0 +1,28 @@
+<!--
+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="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M12.0,7.0c-2.9,0.0 -5.25,2.35 -5.25,5.25C6.75,16.19 12.0,22.0 12.0,22.0s5.25,-5.81 5.25,-9.75C17.25,9.35 14.9,7.0 12.0,7.0zM12.0,14.12c-1.04,0.0 -1.88,-0.84 -1.88,-1.88s0.84,-1.88 1.88,-1.88c1.04,0.0 1.87,0.84 1.87,1.88S13.04,14.12 12.0,14.12z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_04.xml b/packages/SystemUI/res/drawable/ic_location_24_04.xml
new file mode 100644
index 0000000..0c0fb3b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_04.xml
@@ -0,0 +1,28 @@
+<!--
+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="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M12.0,10.0c-2.32,0.0 -4.2,1.88 -4.2,4.2C7.8,17.35 12.0,22.0 12.0,22.0s4.2,-4.65 4.2,-7.8C16.2,11.88 14.32,10.0 12.0,10.0zM12.0,15.7c-0.83,0.0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5c0.83,0.0 1.5,0.67 1.5,1.5S12.83,15.7 12.0,15.7z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_05.xml b/packages/SystemUI/res/drawable/ic_location_24_05.xml
new file mode 100644
index 0000000..1a21e2f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_05.xml
@@ -0,0 +1,28 @@
+<!--
+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="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M12.0,13.0c-1.74,0.0 -3.15,1.41 -3.15,3.15C8.85,18.51 12.0,22.0 12.0,22.0s3.15,-3.49 3.15,-5.85C15.15,14.41 13.74,13.0 12.0,13.0zM12.0,17.27c-0.62,0.0 -1.13,-0.5 -1.13,-1.12c0.0,-0.62 0.5,-1.12 1.13,-1.12c0.62,0.0 1.12,0.5 1.12,1.12C13.12,16.77 12.62,17.27 12.0,17.27z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_06.xml b/packages/SystemUI/res/drawable/ic_location_24_06.xml
new file mode 100644
index 0000000..25c9ae5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_06.xml
@@ -0,0 +1,33 @@
+<!--
+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="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M12.0,16.0c-1.16,0.0 -2.1,0.94 -2.1,2.1C9.9,19.67 12.0,22.0 12.0,22.0s2.1,-2.33 2.1,-3.9C14.1,16.94 13.16,16.0 12.0,16.0zM12.0,18.85c-0.41,0.0 -0.75,-0.34 -0.75,-0.75s0.34,-0.75 0.75,-0.75c0.41,0.0 0.75,0.34 0.75,0.75S12.41,18.85 12.0,18.85z"/>
+ <path
+ android:pathData="M11.99,15c-1.35,0,-2.45,1.1,-2.45,2.45 c0,1.84,2.45,4.55,2.45,4.55s2.45,-2.71,2.45,-4.55C14.44,16.1,13.34,15,11.99,15z M11.99,18.33c-0.48,0,-0.88,-0.39,-0.88,-0.88 s0.39,-0.88,0.88,-0.88c0.48,0,0.87,0.39,0.87,0.88S12.47,18.33,11.99,18.33z"
+ android:strokeWidth=".35"
+ android:fill="#00000000"
+ android:stroke="#CCCCCC"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_07.xml b/packages/SystemUI/res/drawable/ic_location_24_07.xml
new file mode 100644
index 0000000..a69c3a2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_07.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="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:pathData="M12,9c-2.51,0,-4.55,2.04,-4.55,4.55 C7.45,16.96,12,22,12,22s4.55,-5.04,4.55,-8.45C16.55,11.04,14.51,9,12,9z M12,15.18c-0.9,0,-1.63,-0.73,-1.63,-1.62 s0.73,-1.62,1.63,-1.62c0.9,0,1.62,0.73,1.62,1.62S12.9,15.18,12,15.18z"
+ android:strokeWidth="0.65"
+ android:fill="#00000000"
+ android:stroke="#CCCCCC"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_08.xml b/packages/SystemUI/res/drawable/ic_location_24_08.xml
new file mode 100644
index 0000000..c89c047
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_08.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="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:pathData="M12,6c-3.09,0,-5.6,2.51,-5.6,5.6 C6.4,15.8,12,22,12,22s5.6,-6.2,5.6,-10.4C17.6,8.51,15.09,6,12,6z M12,13.6c-1.1,0,-2,-0.9,-2,-2s0.9,-2,2,-2c1.1,0,2,0.9,2,2 S13.1,13.6,12,13.6z"
+ android:strokeWidth="0.8"
+ android:fill="#00000000"
+ android:stroke="#CCCCCC"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_09.xml b/packages/SystemUI/res/drawable/ic_location_24_09.xml
new file mode 100644
index 0000000..96bb6ce
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_09.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="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:pathData="M12,4c-3.48,0,-6.3,2.82,-6.3,6.3 C5.7,15.02,12,22,12,22s6.3,-6.98,6.3,-11.7C18.3,6.82,15.48,4,12,4z M12,12.55c-1.24,0,-2.25,-1.01,-2.25,-2.25S10.76,8.05,12,8.05 c1.24,0,2.25,1.01,2.25,2.25S13.24,12.55,12,12.55z"
+ android:strokeWidth="0.9"
+ android:fill="#00000000"
+ android:stroke="#CCCCCC"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_10.xml b/packages/SystemUI/res/drawable/ic_location_24_10.xml
new file mode 100644
index 0000000..aced4bd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_10.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="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:pathData="M12,3C8.33,3,5.35,5.98,5.35,9.65 C5.35,14.64,12,22,12,22s6.65,-7.36,6.65,-12.35C18.65,5.98,15.67,3,12,3z M12,12.02c-1.31,0,-2.38,-1.06,-2.38,-2.38 S10.69,7.28,12,7.28c1.31,0,2.37,1.06,2.37,2.37S13.31,12.02,12,12.02z"
+ android:strokeWidth="0.95"
+ android:fill="#00000000"
+ android:stroke="#CCCCCC"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_11.xml b/packages/SystemUI/res/drawable/ic_location_24_11.xml
new file mode 100644
index 0000000..578308e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_11.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="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:pathData="M12,2C8.13,2,5,5.13,5,9c0,5.25,7,13,7,13s7,-7.75,7,-13 C19,5.13,15.87,2,12,2z M12,11.5c-1.38,0,-2.5,-1.12,-2.5,-2.5s1.12,-2.5,2.5,-2.5c1.38,0,2.5,1.12,2.5,2.5S13.38,11.5,12,11.5z"
+ android:fill="#00000000"
+ android:stroke="#CCCCCC"
+ android:strokeWidth="1.0"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_off_anim.xml b/packages/SystemUI/res/drawable/ic_location_off_anim.xml
new file mode 100644
index 0000000..864eda1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_off_anim.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+<animation-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:oneshot="true">
+ <item android:drawable="@drawable/ic_location_24_01" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_02" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_03" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_04" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_05" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_06" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_07" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_08" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_09" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_10" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_11" android:duration="16" />
+</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_location_on_anim.xml b/packages/SystemUI/res/drawable/ic_location_on_anim.xml
new file mode 100644
index 0000000..65a8afe
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_on_anim.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+<animation-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:oneshot="true">
+ <item android:drawable="@drawable/ic_location_24_11" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_10" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_09" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_08" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_07" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_06" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_05" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_04" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_03" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_02" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_01" android:duration="16" />
+</animation-list>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 7de1bd0..9582b21 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -22,6 +22,7 @@
<drawable name="system_bar_background">@color/system_bar_background_opaque</drawable>
<color name="system_bar_background_opaque">#ff000000</color>
<color name="system_bar_background_semi_transparent">#66000000</color> <!-- 40% black -->
+ <color name="system_bar_background_transparent">#00000000</color>
<color name="notification_panel_solid_background">#ff000000</color>
<drawable name="status_bar_recents_app_thumbnail_background">#88000000</drawable>
<color name="status_bar_recents_app_label_color">#ffffffff</color>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 1273e74..9536b12 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -22,8 +22,9 @@
<!-- Alternate Recents theme -->
<style name="RecentsTheme" parent="@android:style/Theme.DeviceDefault.Wallpaper.NoTitleBar">
- <item name="android:windowTranslucentStatus">true</item>
- <item name="android:windowTranslucentNavigation">true</item>
+ <item name="android:statusBarColor">@android:color/transparent</item>
+ <item name="android:navigationBarColor">@android:color/transparent</item>
+ <item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item>
</style>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index d32f98f..176e05c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles;
+import android.graphics.drawable.AnimationDrawable;
+
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.LocationController;
@@ -56,16 +58,28 @@ public class LocationTile extends QSTile<QSTile.BooleanState> {
protected void handleUpdateState(BooleanState state, Object arg) {
final boolean locationEnabled = mController.isLocationEnabled();
state.visible = true;
- state.value = locationEnabled;
- state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_location);
+ if (state.value != locationEnabled) {
+ state.value = locationEnabled;
+ final AnimationDrawable d = (AnimationDrawable) mContext.getDrawable(locationEnabled
+ ? R.drawable.ic_location_on_anim
+ : R.drawable.ic_location_off_anim);
+ state.icon = d;
+ mUiHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ d.start();
+ }
+ });
+ }
+ //state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_location);
if (locationEnabled) {
- state.iconId = R.drawable.ic_qs_location_on;
+ if (state.icon == null) state.iconId = R.drawable.ic_location_24_01;
state.label = mContext.getString(R.string.quick_settings_location_label);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_location,
mContext.getString(R.string.accessibility_desc_on));
} else {
- state.iconId = R.drawable.ic_qs_location_off;
+ if (state.icon == null) state.iconId = R.drawable.ic_location_24_11;
state.label = mContext.getString(R.string.quick_settings_location_off_label);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_location,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index eb63a54..a41ec22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -43,6 +43,7 @@ public class BarTransitions {
public static final int MODE_SEMI_TRANSPARENT = 1;
public static final int MODE_TRANSLUCENT = 2;
public static final int MODE_LIGHTS_OUT = 3;
+ public static final int MODE_TRANSPARENT = 4;
public static final int LIGHTS_IN_DURATION = 250;
public static final int LIGHTS_OUT_DURATION = 750;
@@ -69,7 +70,8 @@ public class BarTransitions {
public void transitionTo(int mode, boolean animate) {
// low-end devices do not support translucent modes, fallback to opaque
- if (!HIGH_END && (mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSLUCENT)) {
+ if (!HIGH_END && (mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSLUCENT
+ || mode == MODE_TRANSPARENT)) {
mode = MODE_OPAQUE;
}
if (mMode == mode) return;
@@ -97,6 +99,7 @@ public class BarTransitions {
if (mode == MODE_SEMI_TRANSPARENT) return "MODE_SEMI_TRANSPARENT";
if (mode == MODE_TRANSLUCENT) return "MODE_TRANSLUCENT";
if (mode == MODE_LIGHTS_OUT) return "MODE_LIGHTS_OUT";
+ if (mode == MODE_TRANSPARENT) return "MODE_TRANSPARENT";
throw new IllegalArgumentException("Unknown mode " + mode);
}
@@ -111,6 +114,7 @@ public class BarTransitions {
private static class BarBackgroundDrawable extends Drawable {
private final int mOpaque;
private final int mSemiTransparent;
+ private final int mTransparent;
private final Drawable mGradient;
private final TimeInterpolator mInterpolator;
@@ -130,9 +134,11 @@ public class BarTransitions {
if (DEBUG_COLORS) {
mOpaque = 0xff0000ff;
mSemiTransparent = 0x7f0000ff;
+ mTransparent = 0x2f0000ff;
} else {
mOpaque = res.getColor(R.color.system_bar_background_opaque);
mSemiTransparent = res.getColor(R.color.system_bar_background_semi_transparent);
+ mTransparent = res.getColor(R.color.system_bar_background_transparent);
}
mGradient = res.getDrawable(gradientResourceId);
mInterpolator = new LinearInterpolator();
@@ -184,9 +190,11 @@ public class BarTransitions {
public void draw(Canvas canvas) {
int targetGradientAlpha = 0, targetColor = 0;
if (mMode == MODE_TRANSLUCENT) {
- targetGradientAlpha = 0xff;
+ targetColor = mSemiTransparent;
} else if (mMode == MODE_SEMI_TRANSPARENT) {
targetColor = mSemiTransparent;
+ } else if (mMode == MODE_TRANSPARENT) {
+ targetColor = mTransparent;
} else {
targetColor = mOpaque;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index a0582ee..c83b479 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -61,7 +61,7 @@ public final class NavigationBarTransitions extends BarTransitions {
@Override
public void transitionTo(int mode, boolean animate) {
mRequestedMode = mode;
- if (mVertical && mode == MODE_TRANSLUCENT) {
+ if (mVertical && (mode == MODE_TRANSLUCENT || mode == MODE_TRANSPARENT)) {
// translucent mode not allowed when vertical
mode = MODE_OPAQUE;
}
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 23b0594..d3b5f96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -26,6 +26,7 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OU
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -1870,6 +1871,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private int barMode(int vis, int transientFlag, int translucentFlag) {
return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT
: (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT
+ : (vis & View.SYSTEM_UI_TRANSPARENT) != 0 ? MODE_TRANSPARENT
: (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT
: MODE_OPAQUE;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
index 8406565..8520f40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
@@ -68,7 +68,8 @@ public final class PhoneStatusBarTransitions extends BarTransitions {
}
private boolean isOpaque(int mode) {
- return !(mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSLUCENT);
+ return !(mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSLUCENT
+ || mode == MODE_TRANSPARENT);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 46a637b..b7bf6cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -75,8 +75,7 @@ public class StatusBarWindowManager {
| WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
- | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
+ | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
PixelFormat.TRANSLUCENT);
mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
mLp.gravity = Gravity.TOP;
diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/policy/src/com/android/internal/policy/impl/BarController.java
index fc49a569..49e1072 100644
--- a/policy/src/com/android/internal/policy/impl/BarController.java
+++ b/policy/src/com/android/internal/policy/impl/BarController.java
@@ -108,13 +108,20 @@ public class BarController {
if (mWin != null) {
if (win != null && (win.getAttrs().privateFlags
& WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) == 0) {
- if ((PolicyControl.getWindowFlags(win, null) & mTranslucentWmFlag) != 0) {
+ int fl = PolicyControl.getWindowFlags(win, null);
+ if ((fl & mTranslucentWmFlag) != 0) {
vis |= mTranslucentFlag;
} else {
vis &= ~mTranslucentFlag;
}
+ if ((fl & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
+ vis |= View.SYSTEM_UI_TRANSPARENT;
+ } else {
+ vis &= ~View.SYSTEM_UI_TRANSPARENT;
+ }
} else {
vis = (vis & ~mTranslucentFlag) | (oldVis & mTranslucentFlag);
+ vis = (vis & View.SYSTEM_UI_TRANSPARENT) | (oldVis & View.SYSTEM_UI_TRANSPARENT);
}
}
return vis;
@@ -230,7 +237,8 @@ public class BarController {
vis |= mTransientFlag; // ignore clear requests until transition completes
vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE; // never show transient bars in low profile
}
- if ((vis & mTranslucentFlag) != 0 || (oldVis & mTranslucentFlag) != 0) {
+ if ((vis & mTranslucentFlag) != 0 || (oldVis & mTranslucentFlag) != 0 ||
+ ((vis | oldVis) & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0) {
mLastTranslucent = SystemClock.uptimeMillis();
}
return vis;
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index fec9dda..673ce0b 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -183,11 +183,17 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
mDialog = createDialog();
prepareDialog();
- WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
- attrs.setTitle("GlobalActions");
- mDialog.getWindow().setAttributes(attrs);
- mDialog.show();
- mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
+ // If we only have 1 item and it's a simple press action, just do this action.
+ if (mAdapter.getCount() == 1
+ && mAdapter.getItem(0) instanceof SinglePressAction) {
+ ((SinglePressAction) mAdapter.getItem(0)).onPress();
+ } else {
+ WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
+ attrs.setTitle("GlobalActions");
+ mDialog.getWindow().setAttributes(attrs);
+ mDialog.show();
+ mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
+ }
}
/**
@@ -398,7 +404,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
@Override
public boolean showBeforeProvisioning() {
- return false;
+ return true;
}
};
}
@@ -1024,6 +1030,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
mEnableAccessibilityController = null;
super.setCanceledOnTouchOutside(true);
}
+
super.onStart();
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 6341a0c..1b96f1f 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -38,9 +38,7 @@ import com.android.internal.widget.ActionBarOverlayLayout;
import com.android.internal.widget.ActionBarView;
import com.android.internal.widget.SwipeDismissLayout;
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
-import android.app.ActivityOptions;
+import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -49,6 +47,7 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -56,22 +55,15 @@ import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
-import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.transition.ChangeBounds;
-import android.transition.Explode;
-import android.transition.Fade;
-import android.transition.MoveImage;
import android.transition.Scene;
import android.transition.Transition;
import android.transition.TransitionInflater;
import android.transition.TransitionManager;
-import android.transition.TransitionSet;
import android.util.AndroidRuntimeException;
-import android.util.ArrayMap;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -98,7 +90,6 @@ import android.view.ViewManager;
import android.view.ViewParent;
import android.view.ViewRootImpl;
import android.view.ViewStub;
-import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
@@ -113,8 +104,6 @@ import android.widget.TextView;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Map;
/**
* Android-specific Window.
@@ -213,6 +202,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private int mFrameResource = 0;
private int mTextColor = 0;
+ private int mStatusBarColor = 0;
+ private int mNavigationBarColor = 0;
private CharSequence mTitle = null;
@@ -1987,7 +1978,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
- private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
+ private final class DecorView extends FrameLayout implements RootViewSurfaceTaker,
+ View.OnSystemUiVisibilityChangeListener {
/* package */int mDefaultOpacity = PixelFormat.OPAQUE;
/** The feature ID of the panel, or -1 if this is the application's DecorView */
@@ -2017,6 +2009,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// View added at runtime to draw under the navigation bar area
private View mNavigationGuard;
+ private View mStatusColorView;
+ private View mNavigationColorView;
+
+ private int mLastTopInset = 0;
+ private int mLastBottomInset = 0;
+ private int mLastSystemUiVisibility = 0;
+
+
public DecorView(Context context, int featureId) {
super(context);
mFeatureId = featureId;
@@ -2582,8 +2582,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
@Override
+ public void onSystemUiVisibilityChange(int visible) {
+ mLastSystemUiVisibility = visible;
+ updateColorViews(null /* insets */);
+ }
+
+ @Override
protected boolean fitSystemWindows(Rect insets) {
mFrameOffsets.set(insets);
+ updateColorViews(insets);
updateStatusGuard(insets);
updateNavigationGuard(insets);
if (getForeground() != null) {
@@ -2597,6 +2604,52 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
return false;
}
+ private void updateColorViews(Rect insets) {
+ if (mIsFloating || !ActivityManager.isHighEndGfx()) {
+ // No colors on floating windows or low end devices :(
+ return;
+ }
+ if (insets != null) {
+ mLastTopInset = insets.top;
+ mLastBottomInset = insets.bottom;
+ }
+ mStatusColorView = updateColorViewInt(mStatusColorView,
+ SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
+ mStatusBarColor, mLastTopInset, Gravity.TOP);
+ mNavigationColorView = updateColorViewInt(mNavigationColorView,
+ SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
+ mNavigationBarColor, mLastBottomInset, Gravity.BOTTOM);
+ }
+
+ private View updateColorViewInt(View view, int systemUiHideFlag, int translucentFlag,
+ int color, int height, int verticalGravity) {
+ boolean show = height > 0 && (mLastSystemUiVisibility & systemUiHideFlag) == 0
+ && (getAttributes().flags & translucentFlag) == 0
+ && (color & Color.BLACK) != 0
+ && (getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
+
+ if (view == null) {
+ if (show) {
+ view = new View(mContext);
+ view.setBackgroundColor(color);
+ addView(view, new LayoutParams(LayoutParams.MATCH_PARENT, height,
+ Gravity.START | verticalGravity));
+ }
+ } else {
+ int vis = show ? VISIBLE : INVISIBLE;
+ view.setVisibility(vis);
+ if (show) {
+ LayoutParams lp = (LayoutParams) view.getLayoutParams();
+ if (lp.height != height) {
+ lp.height = height;
+ view.setLayoutParams(lp);
+ }
+ view.setBackgroundColor(color);
+ }
+ }
+ return view;
+ }
+
private void updateStatusGuard(Rect insets) {
boolean showStatusGuard = false;
// Show the status guard when the non-overlay contextual action bar is showing
@@ -2616,9 +2669,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mStatusGuard = new View(mContext);
mStatusGuard.setBackgroundColor(mContext.getResources()
.getColor(R.color.input_method_navigation_guard));
- addView(mStatusGuard, new LayoutParams(
- LayoutParams.MATCH_PARENT, mlp.topMargin,
- Gravity.START | Gravity.TOP));
+ addView(mStatusGuard, indexOfChild(mStatusColorView),
+ new LayoutParams(LayoutParams.MATCH_PARENT, mlp.topMargin,
+ Gravity.START | Gravity.TOP));
} else {
LayoutParams lp = (LayoutParams) mStatusGuard.getLayoutParams();
if (lp.height != mlp.topMargin) {
@@ -2663,7 +2716,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mNavigationGuard = new View(mContext);
mNavigationGuard.setBackgroundColor(mContext.getResources()
.getColor(R.color.input_method_navigation_guard));
- addView(mNavigationGuard, new LayoutParams(
+ addView(mNavigationGuard, indexOfChild(mNavigationColorView), new LayoutParams(
LayoutParams.MATCH_PARENT, insets.bottom,
Gravity.START | Gravity.BOTTOM));
} else {
@@ -3009,6 +3062,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
final int targetSdk = context.getApplicationInfo().targetSdkVersion;
final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB;
final boolean targetPreIcs = targetSdk < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
+ final boolean targetPreL = targetSdk < android.os.Build.VERSION_CODES.L;
final boolean targetHcNeedsOptions = context.getResources().getBoolean(
com.android.internal.R.bool.target_honeycomb_needs_options_menu);
final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);
@@ -3018,7 +3072,21 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
} else {
clearFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY);
}
-
+
+ // Non-floating windows on high end devices must put up decor beneath the system bars and
+ // therefore must know about visibility changes of those.
+ if (!mIsFloating && ActivityManager.isHighEndGfx()) {
+ if (!targetPreL && a.getBoolean(
+ com.android.internal.R.styleable.Window_windowDrawsSystemBarBackgrounds,
+ false)) {
+ setFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+ FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS & ~getForcedWindowFlags());
+ }
+ decor.setOnSystemUiVisibilityChangeListener(decor);
+ }
+ mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);
+ mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000);
+
if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
>= android.os.Build.VERSION_CODES.HONEYCOMB) {
if (a.getBoolean(
@@ -3522,6 +3590,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
return (mLeftIconView = (ImageView)findViewById(com.android.internal.R.id.left_icon));
}
+ @Override
+ protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) {
+ super.dispatchWindowAttributesChanged(attrs);
+ if (mDecor != null) {
+ mDecor.updateColorViews(null /* insets */);
+ }
+ }
+
private ProgressBar getCircularProgressBar(boolean shouldInstallDecor) {
if (mCircularProgressBar != null) {
return mCircularProgressBar;
@@ -4166,4 +4242,22 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
void sendCloseSystemWindows(String reason) {
PhoneWindowManager.sendCloseSystemWindows(getContext(), reason);
}
+
+ @Override
+ public int getStatusBarColor() {
+ return 0;
+ }
+
+ @Override
+ public void setStatusBarColor(int color) {
+ }
+
+ @Override
+ public int getNavigationBarColor() {
+ return 0;
+ }
+
+ @Override
+ public void setNavigationBarColor(int color) {
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 4ee8103..8eed414 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -170,7 +170,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.STATUS_BAR_TRANSLUCENT
- | View.NAVIGATION_BAR_TRANSLUCENT;
+ | View.NAVIGATION_BAR_TRANSLUCENT
+ | View.SYSTEM_UI_TRANSPARENT;
/**
* Keyguard stuff
@@ -1368,6 +1369,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// The status bar is the only window allowed to exhibit keyguard behavior.
attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
}
+
+ if (ActivityManager.isHighEndGfx()
+ && (attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
+ attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+ }
}
void readLidState() {
@@ -2708,7 +2716,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// drive nav being hidden only by whether it is requested.
final int sysui = mLastSystemUiFlags;
boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
- boolean navTranslucent = (sysui & View.NAVIGATION_BAR_TRANSLUCENT) != 0;
+ boolean navTranslucent = (sysui
+ & (View.NAVIGATION_BAR_TRANSLUCENT | View.SYSTEM_UI_TRANSPARENT)) != 0;
boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
boolean navAllowedHidden = immersive || immersiveSticky;
@@ -2834,7 +2843,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mStableTop = mUnrestrictedScreenTop + mStatusBarHeight;
boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
- boolean statusBarTranslucent = (sysui & View.STATUS_BAR_TRANSLUCENT) != 0;
+ boolean statusBarTranslucent = (sysui
+ & (View.STATUS_BAR_TRANSLUCENT | View.SYSTEM_UI_TRANSPARENT)) != 0;
statusBarTranslucent &= areTranslucentBarsAllowed();
// If the status bar is hidden, we don't want to cause
@@ -3030,12 +3040,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (isAppWindow && !inheritTranslucentDecor && !topAtRest) {
if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
&& (fl & WindowManager.LayoutParams.FLAG_FULLSCREEN) == 0
- && (fl & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) == 0) {
+ && (fl & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) == 0
+ && (fl & WindowManager.LayoutParams.
+ FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) {
// Ensure policy decor includes status bar
dcf.top = mStableTop;
}
if ((fl & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) == 0
- && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
+ && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
+ && (fl & WindowManager.LayoutParams.
+ FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) {
// Ensure policy decor includes navigation bar
dcf.bottom = mStableBottom;
dcf.right = mStableRight;
@@ -5232,7 +5246,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
if (!areTranslucentBarsAllowed()) {
- vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSLUCENT);
+ vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSLUCENT
+ | View.SYSTEM_UI_TRANSPARENT);
}
// update status bar
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 0708e55..982dce0 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5491,10 +5491,29 @@ public class ConnectivityService extends IConnectivityManager.Stub {
} catch (Exception e) {
loge("Exception in setDnsServersForNetwork: " + e);
}
- // TODO - setprop "net.dnsX"
+ NetworkAgentInfo defaultNai = mNetworkForRequestId.get(mDefaultRequest.requestId);
+ if (defaultNai != null && defaultNai.network.netId == netId) {
+ setDefaultDnsSystemProperties(dnses);
+ }
}
}
+ private void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) {
+ int last = 0;
+ for (InetAddress dns : dnses) {
+ ++last;
+ String key = "net.dns" + last;
+ String value = dns.getHostAddress();
+ SystemProperties.set(key, value);
+ }
+ for (int i = last + 1; i <= mNumDnsEntries; ++i) {
+ String key = "net.dns" + i;
+ SystemProperties.set(key, "");
+ }
+ mNumDnsEntries = last;
+ }
+
+
private void updateCapabilities(NetworkAgentInfo networkAgent,
NetworkCapabilities networkCapabilities) {
// TODO - what else here? Verify still satisfies everybody?
@@ -5610,6 +5629,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (mDefaultRequest.requestId == nri.request.requestId) {
isNewDefault = true;
updateActiveDefaultNetwork(newNetwork);
+ if (newNetwork.linkProperties != null) {
+ setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnses());
+ } else {
+ setDefaultDnsSystemProperties(new ArrayList<InetAddress>());
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index dd12a65..908bfbd 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -27,6 +27,7 @@ import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Parcel;
+import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -40,6 +41,7 @@ import android.util.Slog;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.PowerProfile;
+import com.android.server.LocalServices;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -49,7 +51,8 @@ import java.util.List;
* All information we are collecting about things that can happen that impact
* battery life.
*/
-public final class BatteryStatsService extends IBatteryStats.Stub {
+public final class BatteryStatsService extends IBatteryStats.Stub
+ implements PowerManagerInternal.LowPowerModeListener {
static final String TAG = "BatteryStatsService";
static IBatteryStats sService;
@@ -58,6 +61,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
Context mContext;
private boolean mBluetoothPendingStats;
private BluetoothHeadset mBluetoothHeadset;
+ PowerManagerInternal mPowerManagerInternal;
BatteryStatsService(String filename, Handler handler) {
mStats = new BatteryStatsImpl(filename, handler);
@@ -70,6 +74,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
mStats.setRadioScanningTimeout(mContext.getResources().getInteger(
com.android.internal.R.integer.config_radioScanningTimeout)
* 1000L);
+ mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
+ mPowerManagerInternal.registerLowPowerModeObserver(this);
+ mStats.noteLowPowerMode(mPowerManagerInternal.getLowPowerModeEnabled());
(new WakeupReasonThread()).start();
}
@@ -88,7 +95,14 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
sService = asInterface(b);
return sService;
}
-
+
+ @Override
+ public void onLowPowerModeChanged(boolean enabled) {
+ synchronized (mStats) {
+ mStats.noteLowPowerMode(enabled);
+ }
+ }
+
/**
* @return the current statistics object, which may be modified
* to reflect events that affect battery usage. You must lock the
@@ -154,11 +168,11 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
}
}
- public void noteStopWakelock(int uid, int pid, String name, int type) {
+ public void noteStopWakelock(int uid, int pid, String name, String historyName, int type) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.noteStopWakeLocked(uid, pid, name, type, SystemClock.elapsedRealtime(),
- SystemClock.uptimeMillis());
+ mStats.noteStopWakeLocked(uid, pid, name, historyName, type,
+ SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
}
}
@@ -171,20 +185,21 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
}
}
- public void noteChangeWakelockFromSource(WorkSource ws, int pid, String name, int type,
- WorkSource newWs, int newPid, String newName,
+ public void noteChangeWakelockFromSource(WorkSource ws, int pid, String name,
+ String historyName, int type, WorkSource newWs, int newPid, String newName,
String newHistoryName, int newType, boolean newUnimportantForLogging) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.noteChangeWakelockFromSourceLocked(ws, pid, name, type,
+ mStats.noteChangeWakelockFromSourceLocked(ws, pid, name, historyName, type,
newWs, newPid, newName, newHistoryName, newType, newUnimportantForLogging);
}
}
- public void noteStopWakelockFromSource(WorkSource ws, int pid, String name, int type) {
+ public void noteStopWakelockFromSource(WorkSource ws, int pid, String name, String historyName,
+ int type) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.noteStopWakeFromSourceLocked(ws, pid, name, type);
+ mStats.noteStopWakeFromSourceLocked(ws, pid, name, historyName, type);
}
}
@@ -608,10 +623,31 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
pw.println(" --charged: only output data since last charged.");
pw.println(" --reset: reset the stats, clearing all current data.");
pw.println(" --write: force write current collected stats to disk.");
+ pw.println(" --enable: enable an option: full-wake-history.");
+ pw.println(" --disable: disable an option: full-wake-history.");
pw.println(" -h: print this help text.");
pw.println(" <package.name>: optional name of package to filter output by.");
}
+ private int doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable) {
+ i++;
+ if (i >= args.length) {
+ pw.println("Missing option argument for " + (enable ? "--enable" : "--disable"));
+ dumpHelp(pw);
+ return -1;
+ }
+ if ("full-wake-history".equals(args[i])) {
+ synchronized (mStats) {
+ mStats.setRecordAllWakeLocksLocked(enable);
+ }
+ } else {
+ pw.println("Unknown enable/disable option: " + args[i]);
+ dumpHelp(pw);
+ return -1;
+ }
+ return i;
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -662,6 +698,20 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
pw.println("Battery stats written.");
noOutput = true;
}
+ } else if ("--enable".equals(arg)) {
+ i = doEnableOrDisable(pw, i, args, true);
+ if (i < 0) {
+ return;
+ }
+ pw.println("Enabled: " + args[i]);
+ return;
+ } else if ("--disable".equals(arg)) {
+ i = doEnableOrDisable(pw, i, args, false);
+ if (i < 0) {
+ return;
+ }
+ pw.println("Disabled: " + args[i]);
+ return;
} else if ("-h".equals(arg)) {
dumpHelp(pw);
return;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index fc6183c..6d2b83b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -58,14 +58,14 @@ public class HdmiCecMessageBuilder {
}
/**
- * Build &lt;Get Osd Name&gt; command.
+ * Build &lt;Give Osd Name&gt; command.
*
* @param src source address of command
* @param dest destination address of command
* @return newly created {@link HdmiCecMessage}
*/
- static HdmiCecMessage buildGetOsdNameCommand(int src, int dest) {
- return buildCommand(src, dest, HdmiCec.MESSAGE_GET_OSD_NAME);
+ static HdmiCecMessage buildGiveOsdNameCommand(int src, int dest) {
+ return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_OSD_NAME);
}
/**
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index c122645..ed48c12 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -127,8 +127,8 @@ public final class HdmiControlService extends SystemService {
case HdmiCec.MESSAGE_GET_MENU_LANGUAGE:
handleGetMenuLanguage(message);
return true;
- case HdmiCec.MESSAGE_GET_OSD_NAME:
- handleGetOsdName(message);
+ case HdmiCec.MESSAGE_GIVE_OSD_NAME:
+ handleGiveOsdName(message);
return true;
case HdmiCec.MESSAGE_GIVE_PHYSICAL_ADDRESS:
handleGivePhysicalAddress(message);
@@ -170,7 +170,7 @@ public final class HdmiControlService extends SystemService {
sendCecCommand(cecMessage);
}
- private void handleGetOsdName(HdmiCecMessage message) {
+ private void handleGiveOsdName(HdmiCecMessage message) {
// TODO: read device name from settings or property.
String name = HdmiCec.getDefaultDeviceName(message.getDestination());
HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildSetOsdNameCommand(
diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
index 98da280..e0bc718 100644
--- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java
+++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
@@ -71,7 +71,7 @@ final class NewDeviceAction extends FeatureAction {
@Override
public boolean start() {
sendCommand(
- HdmiCecMessageBuilder.buildGetOsdNameCommand(mSourceAddress,
+ HdmiCecMessageBuilder.buildGiveOsdNameCommand(mSourceAddress,
mDeviceLogicalAddress));
mState = STATE_WAITING_FOR_SET_OSD_NAME;
addTimer(mState, TIMEOUT_MS);
diff --git a/services/core/java/com/android/server/media/MediaRouteProviderProxy.java b/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
index c4e2058..1c5cacd 100644
--- a/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
@@ -58,12 +58,16 @@ public class MediaRouteProviderProxy {
private final int mUserId;
// Interfaces declared in the manifest
private final ArrayList<String> mInterfaces = new ArrayList<String>();
- private final ArrayList<RouteConnectionRecord> mConnections = new ArrayList<RouteConnectionRecord>();
+ private final ArrayList<RouteConnectionRecord> mConnections
+ = new ArrayList<RouteConnectionRecord>();
+ // The sessions that have a route from this provider selected
+ private final ArrayList<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>();
private final Handler mHandler = new Handler();
private Intent mBindIntent;
private IRouteProvider mBinder;
private boolean mRunning;
+ private boolean mPaused;
private boolean mInterested;
private boolean mBound;
private int mRetryCount;
@@ -83,6 +87,12 @@ public class MediaRouteProviderProxy {
mBindIntent.setComponent(mComponentName);
}
+ public void destroy() {
+ stop();
+ mSessions.clear();
+ updateBinding();
+ }
+
/**
* Send any cleanup messages and unbind from the media route provider
*/
@@ -236,6 +246,19 @@ public class MediaRouteProviderProxy {
return mId;
}
+ public void addSession(MediaSessionRecord session) {
+ mSessions.add(session);
+ }
+
+ public void removeSession(MediaSessionRecord session) {
+ mSessions.remove(session);
+ updateBinding();
+ }
+
+ public int getSessionCount() {
+ return mSessions.size();
+ }
+
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + mId + " " + this);
String indent = prefix + " ";
@@ -257,8 +280,10 @@ public class MediaRouteProviderProxy {
}
}
+ // We want to bind as long as we're interested in this provider or there are
+ // sessions connected to it.
private boolean shouldBind() {
- return mRunning && mInterested;
+ return (mRunning && mInterested) || (!mSessions.isEmpty());
}
private void bind() {
diff --git a/services/core/java/com/android/server/media/MediaRouteProviderWatcher.java b/services/core/java/com/android/server/media/MediaRouteProviderWatcher.java
index cf1d95a..734eab9 100644
--- a/services/core/java/com/android/server/media/MediaRouteProviderWatcher.java
+++ b/services/core/java/com/android/server/media/MediaRouteProviderWatcher.java
@@ -90,6 +90,8 @@ public class MediaRouteProviderWatcher {
}
}
+ // Stop discovering providers and routes. Providers that still have an
+ // active session connected to them will not unbind.
public void stop() {
if (mRunning) {
mRunning = false;
@@ -97,13 +99,21 @@ public class MediaRouteProviderWatcher {
mContext.unregisterReceiver(mScanPackagesReceiver);
mHandler.removeCallbacks(mScanPackagesRunnable);
- // Stop all providers.
+ // Stop all inactive providers.
for (int i = mProviders.size() - 1; i >= 0; i--) {
mProviders.get(i).stop();
}
}
}
+ // Clean up the providers forcibly unbinding if necessary
+ public void destroy() {
+ for (int i = mProviders.size() - 1; i >= 0; i--) {
+ mProviders.get(i).destroy();
+ mProviders.remove(i);
+ }
+ }
+
public ArrayList<MediaRouteProviderProxy> getProviders() {
return mProviders;
}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 41ab626..9677577 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -113,6 +113,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
// End TransportPerformer fields
private boolean mIsActive = false;
+ private boolean mDestroyed = false;
public MediaSessionRecord(int ownerPid, int ownerUid, int userId, String ownerPackageName,
ISessionCallback cb, String tag, MediaSessionService service, Handler handler) {
@@ -220,10 +221,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
public void selectRoute(RouteInfo route) {
synchronized (mLock) {
if (route != mRoute) {
- if (mConnection != null) {
- mConnection.disconnect();
- mConnection = null;
- }
+ disconnect(Session.DISCONNECT_REASON_ROUTE_CHANGED);
}
mRoute = route;
}
@@ -261,14 +259,19 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
public boolean setRouteConnected(RouteInfo route, RouteOptions request,
RouteConnectionRecord connection) {
synchronized (mLock) {
+ if (mDestroyed) {
+ Log.i(TAG, "setRouteConnected: session has been destroyed");
+ connection.disconnect();
+ return false;
+ }
if (mRoute == null || !TextUtils.equals(route.getId(), mRoute.getId())) {
Log.w(TAG, "setRouteConnected: connected route is stale");
- // TODO figure out disconnection path
+ connection.disconnect();
return false;
}
if (request != mRequest) {
Log.w(TAG, "setRouteConnected: connection request is stale");
- // TODO figure out disconnection path
+ connection.disconnect();
return false;
}
mConnection = connection;
@@ -284,7 +287,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
* @return True if the session is active, false otherwise.
*/
public boolean isActive() {
- return mIsActive;
+ return mIsActive && !mDestroyed;
}
/**
@@ -307,6 +310,30 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
return false;
}
+ /**
+ * @return True if this session is currently connected to a route.
+ */
+ public boolean isConnected() {
+ return mConnection != null;
+ }
+
+ public void disconnect(int reason) {
+ synchronized (mLock) {
+ if (!mDestroyed) {
+ disconnectLocked(reason);
+ }
+ }
+ }
+
+ private void disconnectLocked(int reason) {
+ if (mConnection != null) {
+ mConnection.setListener(null);
+ mConnection.disconnect();
+ mConnection = null;
+ pushDisconnected(reason);
+ }
+ }
+
public boolean isTransportControlEnabled() {
return hasFlag(Session.FLAG_HANDLES_TRANSPORT_CONTROLS);
}
@@ -316,6 +343,28 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
mService.sessionDied(this);
}
+ /**
+ * Finish cleaning up this session, including disconnecting if connected and
+ * removing the death observer from the callback binder.
+ */
+ public void onDestroy() {
+ synchronized (mLock) {
+ if (mDestroyed) {
+ return;
+ }
+ if (isConnected()) {
+ disconnectLocked(Session.DISCONNECT_REASON_SESSION_DESTROYED);
+ }
+ mRoute = null;
+ mRequest = null;
+ mDestroyed = true;
+ }
+ }
+
+ public ISessionCallback getCallback() {
+ return mSessionCb.mCb;
+ }
+
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + mTag + " " + this);
@@ -323,7 +372,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
pw.println(indent + "ownerPid=" + mOwnerPid + ", ownerUid=" + mOwnerUid
+ ", userId=" + mUserId);
pw.println(indent + "info=" + mSessionInfo.toString());
- pw.println(indent + "published=" + mIsActive);
+ pw.println(indent + "active=" + mIsActive);
pw.println(indent + "flags=" + mFlags);
pw.println(indent + "rating type=" + mRatingType);
pw.println(indent + "controllers: " + mControllerCallbacks.size());
@@ -356,12 +405,17 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
return "size=" + fields + ", title=" + title;
}
- private void onDestroy() {
- mService.destroySession(this);
+ private void pushDisconnected(int reason) {
+ synchronized (mLock) {
+ mSessionCb.sendRouteDisconnected(reason);
+ }
}
private void pushPlaybackStateUpdate() {
synchronized (mLock) {
+ if (mDestroyed) {
+ return;
+ }
for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
ISessionControllerCallback cb = mControllerCallbacks.get(i);
try {
@@ -376,6 +430,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
private void pushMetadataUpdate() {
synchronized (mLock) {
+ if (mDestroyed) {
+ return;
+ }
for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
ISessionControllerCallback cb = mControllerCallbacks.get(i);
try {
@@ -390,6 +447,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
private void pushRouteUpdate() {
synchronized (mLock) {
+ if (mDestroyed) {
+ return;
+ }
for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
ISessionControllerCallback cb = mControllerCallbacks.get(i);
try {
@@ -404,6 +464,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
private void pushEvent(String event, Bundle data) {
synchronized (mLock) {
+ if (mDestroyed) {
+ return;
+ }
for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
ISessionControllerCallback cb = mControllerCallbacks.get(i);
try {
@@ -417,6 +480,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
private void pushRouteCommand(RouteCommand command, ResultReceiver cb) {
synchronized (mLock) {
+ if (mDestroyed) {
+ return;
+ }
if (mRoute == null || !TextUtils.equals(command.getRouteInfo(), mRoute.getId())) {
if (cb != null) {
cb.send(RouteInterface.RESULT_ROUTE_IS_STALE, null);
@@ -470,14 +536,14 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
@Override
public void disconnect() {
- // TODO
+ MediaSessionRecord.this.disconnect(Session.DISCONNECT_REASON_PROVIDER_DISCONNECTED);
}
};
private final class SessionStub extends ISession.Stub {
@Override
public void destroy() {
- onDestroy();
+ mService.destroySession(MediaSessionRecord.this);
}
@Override
@@ -554,6 +620,14 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
@Override
+ public void disconnectFromRoute(RouteInfo route) {
+ if (route != null && mRoute != null
+ && TextUtils.equals(route.getId(), mRoute.getId())) {
+ disconnect(Session.DISCONNECT_REASON_SESSION_DISCONNECTED);
+ }
+ }
+
+ @Override
public void setRouteOptions(List<RouteOptions> options) throws RemoteException {
mRequests.clear();
for (int i = options.size() - 1; i >= 0; i--) {
@@ -621,6 +695,14 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
}
+ public void sendRouteDisconnected(int reason) {
+ try {
+ mCb.onRouteDisconnected(mRoute, reason);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in sendRouteDisconnected");
+ }
+ }
+
public void play() {
try {
mCb.onPlay();
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 008f9be..78f3b5f 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -24,20 +24,19 @@ 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.media.session.Session;
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;
+import android.util.SparseArray;
import com.android.server.SystemService;
import com.android.server.Watchdog;
@@ -56,16 +55,18 @@ public class MediaSessionService extends SystemService implements Monitor {
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final SessionManagerImpl mSessionManagerImpl;
- private final MediaRouteProviderWatcher mRouteProviderWatcher;
+ // private final MediaRouteProviderWatcher mRouteProviderWatcher;
private final MediaSessionStack mPriorityStack;
- private final ArrayList<MediaSessionRecord> mRecords = new ArrayList<MediaSessionRecord>();
- private final ArrayList<MediaRouteProviderProxy> mProviders
- = new ArrayList<MediaRouteProviderProxy>();
+ private final ArrayList<MediaSessionRecord> mAllSessions = new ArrayList<MediaSessionRecord>();
+ private final SparseArray<UserRecord> mUserRecords = new SparseArray<UserRecord>();
+ // private final ArrayList<MediaRouteProviderProxy> mProviders
+ // = new ArrayList<MediaRouteProviderProxy>();
private final Object mLock = new Object();
private final Handler mHandler = new Handler();
private MediaSessionRecord mPrioritySession;
+ private int mCurrentUserId = -1;
// Used to keep track of the current request to show routes for a specific
// session so we drop late callbacks properly.
@@ -77,16 +78,14 @@ public class MediaSessionService extends SystemService implements Monitor {
public MediaSessionService(Context context) {
super(context);
mSessionManagerImpl = new SessionManagerImpl();
- mRouteProviderWatcher = new MediaRouteProviderWatcher(context, mProviderWatcherCallback,
- mHandler, context.getUserId());
mPriorityStack = new MediaSessionStack();
}
@Override
public void onStart() {
publishBinderService(Context.MEDIA_SESSION_SERVICE, mSessionManagerImpl);
- mRouteProviderWatcher.start();
Watchdog.getInstance().addMonitor(this);
+ updateUser();
}
/**
@@ -98,16 +97,28 @@ public class MediaSessionService extends SystemService implements Monitor {
public void showRoutePickerForSession(MediaSessionRecord record) {
// TODO for now just toggle the route to test (we will only have one
// match for now)
- if (record.getRoute() != null) {
- // For now send null to mean the local route
- record.selectRoute(null);
- return;
- }
- mShowRoutesRequestId++;
- ArrayList<MediaRouteProviderProxy> providers = mRouteProviderWatcher.getProviders();
- for (int i = providers.size() - 1; i >= 0; i--) {
- MediaRouteProviderProxy provider = providers.get(i);
- provider.getRoutes(record, mShowRoutesRequestId);
+ synchronized (mLock) {
+ if (!mAllSessions.contains(record)) {
+ Log.d(TAG, "Unknown session tried to show route picker. Ignoring.");
+ return;
+ }
+ RouteInfo current = record.getRoute();
+ UserRecord user = mUserRecords.get(record.getUserId());
+ if (current != null) {
+ // For now send null to mean the local route
+ MediaRouteProviderProxy proxy = user.getProviderLocked(current.getProvider());
+ if (proxy != null) {
+ proxy.removeSession(record);
+ }
+ record.selectRoute(null);
+ return;
+ }
+ ArrayList<MediaRouteProviderProxy> providers = user.getProvidersLocked();
+ mShowRoutesRequestId++;
+ for (int i = providers.size() - 1; i >= 0; i--) {
+ MediaRouteProviderProxy provider = providers.get(i);
+ provider.getRoutes(record, mShowRoutesRequestId);
+ }
}
}
@@ -121,19 +132,31 @@ public class MediaSessionService extends SystemService implements Monitor {
public void connectToRoute(MediaSessionRecord session, RouteInfo route,
RouteOptions options) {
synchronized (mLock) {
- MediaRouteProviderProxy proxy = getProviderLocked(route.getProvider());
+ if (!mAllSessions.contains(session)) {
+ Log.d(TAG, "Unknown session attempting to connect to route. Ignoring");
+ return;
+ }
+ UserRecord user = mUserRecords.get(session.getUserId());
+ if (user == null) {
+ Log.wtf(TAG, "connectToRoute: User " + session.getUserId() + " does not exist.");
+ return;
+ }
+ MediaRouteProviderProxy proxy = user.getProviderLocked(route.getProvider());
if (proxy == null) {
Log.w(TAG, "Provider for route " + route.getName() + " does not exist.");
return;
}
RouteRequest request = new RouteRequest(session.getSessionInfo(), options, true);
- // TODO make connect an async call to a ThreadPoolExecutor
proxy.connectToRoute(session, route, request);
}
}
public void updateSession(MediaSessionRecord record) {
synchronized (mLock) {
+ if (!mAllSessions.contains(record)) {
+ Log.d(TAG, "Unknown session updated. Ignoring.");
+ return;
+ }
mPriorityStack.onSessionStateChange(record);
if (record.isSystemPriority()) {
if (record.isActive()) {
@@ -152,17 +175,48 @@ public class MediaSessionService extends SystemService implements Monitor {
public void onSessionPlaystateChange(MediaSessionRecord record, int oldState, int newState) {
synchronized (mLock) {
+ if (!mAllSessions.contains(record)) {
+ Log.d(TAG, "Unknown session changed playback state. Ignoring.");
+ return;
+ }
mPriorityStack.onPlaystateChange(record, oldState, newState);
}
}
@Override
+ public void onStartUser(int userHandle) {
+ updateUser();
+ }
+
+ @Override
+ public void onSwitchUser(int userHandle) {
+ updateUser();
+ }
+
+ @Override
+ public void onStopUser(int userHandle) {
+ synchronized (mLock) {
+ UserRecord user = mUserRecords.get(userHandle);
+ if (user != null) {
+ destroyUserLocked(user);
+ }
+ }
+ }
+
+ @Override
public void monitor() {
synchronized (mLock) {
// Check for deadlock
}
}
+ 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.");
+ }
+ }
+
void sessionDied(MediaSessionRecord session) {
synchronized (mLock) {
destroySessionLocked(session);
@@ -175,12 +229,63 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
+ private void updateUser() {
+ synchronized (mLock) {
+ int userId = ActivityManager.getCurrentUser();
+ if (mCurrentUserId != userId) {
+ final int oldUserId = mCurrentUserId;
+ mCurrentUserId = userId; // do this first
+
+ UserRecord oldUser = mUserRecords.get(oldUserId);
+ if (oldUser != null) {
+ oldUser.stopLocked();
+ }
+
+ UserRecord newUser = getOrCreateUser(userId);
+ newUser.startLocked();
+ }
+ }
+ }
+
+ /**
+ * Stop the user and unbind from everything.
+ *
+ * @param user The user to dispose of
+ */
+ private void destroyUserLocked(UserRecord user) {
+ user.stopLocked();
+ user.destroyLocked();
+ mUserRecords.remove(user.mUserId);
+ }
+
+ /*
+ * When a session is removed several things need to happen.
+ * 1. We need to remove it from the relevant user.
+ * 2. We need to remove it from the priority stack.
+ * 3. We need to remove it from all sessions.
+ * 4. If this is the system priority session we need to clear it.
+ * 5. We need to unlink to death from the cb binder
+ * 6. We need to tell the session to do any final cleanup (onDestroy)
+ */
private void destroySessionLocked(MediaSessionRecord session) {
- mRecords.remove(session);
+ int userId = session.getUserId();
+ UserRecord user = mUserRecords.get(userId);
+ if (user != null) {
+ user.removeSessionLocked(session);
+ }
+
mPriorityStack.removeSession(session);
+ mAllSessions.remove(session);
if (session == mPrioritySession) {
mPrioritySession = null;
}
+
+ try {
+ session.getCallback().asBinder().unlinkToDeath(session, 0);
+ } catch (Exception e) {
+ // ignore exceptions while destroying a session.
+ }
+ session.onDestroy();
}
private void enforcePackageName(String packageName, int uid) {
@@ -197,13 +302,6 @@ public class MediaSessionService extends SystemService implements Monitor {
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:
@@ -271,14 +369,22 @@ public class MediaSessionService extends SystemService implements Monitor {
}
private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
- String callerPackageName, ISessionCallback cb, String tag) {
+ String callerPackageName, ISessionCallback cb, String tag) throws RemoteException {
synchronized (mLock) {
return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb, tag);
}
}
+ /*
+ * When a session is created the following things need to happen.
+ * 1. It's callback binder needs a link to death
+ * 2. It needs to be added to all sessions.
+ * 3. It needs to be added to the priority stack.
+ * 4. It needs to be added to the relevant user record.
+ */
private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId,
String callerPackageName, ISessionCallback cb, String tag) {
+
final MediaSessionRecord session = new MediaSessionRecord(callerPid, callerUid, userId,
callerPackageName, cb, tag, this, mHandler);
try {
@@ -286,17 +392,31 @@ public class MediaSessionService extends SystemService implements Monitor {
} catch (RemoteException e) {
throw new RuntimeException("Media Session owner died prematurely.", e);
}
- mRecords.add(session);
+
+ mAllSessions.add(session);
mPriorityStack.addSession(session);
+
+ UserRecord user = getOrCreateUser(userId);
+ user.addSessionLocked(session);
+
if (DEBUG) {
Log.d(TAG, "Created session for package " + callerPackageName + " with tag " + tag);
}
return session;
}
+ private UserRecord getOrCreateUser(int userId) {
+ UserRecord user = mUserRecords.get(userId);
+ if (user == null) {
+ user = new UserRecord(getContext(), userId);
+ mUserRecords.put(userId, user);
+ }
+ return user;
+ }
+
private int findIndexOfSessionForIdLocked(String sessionId) {
- for (int i = mRecords.size() - 1; i >= 0; i--) {
- MediaSessionRecord session = mRecords.get(i);
+ for (int i = mAllSessions.size() - 1; i >= 0; i--) {
+ MediaSessionRecord session = mAllSessions.get(i);
if (TextUtils.equals(session.getSessionInfo().getId(), sessionId)) {
return i;
}
@@ -304,42 +424,11 @@ public class MediaSessionService extends SystemService implements Monitor {
return -1;
}
- private MediaRouteProviderProxy getProviderLocked(String providerId) {
- for (int i = mProviders.size() - 1; i >= 0; i--) {
- MediaRouteProviderProxy provider = mProviders.get(i);
- if (TextUtils.equals(providerId, provider.getId())) {
- return provider;
- }
- }
- return null;
- }
-
private boolean isSessionDiscoverable(MediaSessionRecord record) {
- // TODO probably want to check more than if it's published.
+ // TODO probably want to check more than if it's active.
return record.isActive();
}
- private MediaRouteProviderWatcher.Callback mProviderWatcherCallback
- = new MediaRouteProviderWatcher.Callback() {
- @Override
- public void removeProvider(MediaRouteProviderProxy provider) {
- synchronized (mLock) {
- mProviders.remove(provider);
- provider.setRoutesListener(null);
- provider.setInterested(false);
- }
- }
-
- @Override
- public void addProvider(MediaRouteProviderProxy provider) {
- synchronized (mLock) {
- mProviders.add(provider);
- provider.setRoutesListener(mRoutesCallback);
- provider.setInterested(true);
- }
- }
- };
-
private MediaRouteProviderProxy.RoutesListener mRoutesCallback
= new MediaRouteProviderProxy.RoutesListener() {
@Override
@@ -350,8 +439,12 @@ public class MediaSessionService extends SystemService implements Monitor {
synchronized (mLock) {
int index = findIndexOfSessionForIdLocked(sessionId);
if (index != -1 && routes != null && routes.size() > 0) {
- MediaSessionRecord record = mRecords.get(index);
- record.selectRoute(routes.get(0));
+ MediaSessionRecord record = mAllSessions.get(index);
+ RouteInfo route = routes.get(0);
+ record.selectRoute(route);
+ UserRecord user = mUserRecords.get(record.getUserId());
+ MediaRouteProviderProxy provider = user.getProviderLocked(route.getProvider());
+ provider.addSession(record);
}
}
}
@@ -362,13 +455,135 @@ public class MediaSessionService extends SystemService implements Monitor {
synchronized (mLock) {
int index = findIndexOfSessionForIdLocked(sessionId);
if (index != -1) {
- MediaSessionRecord session = mRecords.get(index);
+ MediaSessionRecord session = mAllSessions.get(index);
session.setRouteConnected(route, options.getConnectionOptions(), connection);
}
}
}
};
+ /**
+ * Information about a particular user. The contents of this object is
+ * guarded by mLock.
+ */
+ final class UserRecord {
+ private final int mUserId;
+ private final MediaRouteProviderWatcher mRouteProviderWatcher;
+ private final ArrayList<MediaRouteProviderProxy> mProviders
+ = new ArrayList<MediaRouteProviderProxy>();
+ private final ArrayList<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>();
+
+ public UserRecord(Context context, int userId) {
+ mUserId = userId;
+ mRouteProviderWatcher = new MediaRouteProviderWatcher(context,
+ mProviderWatcherCallback, mHandler, userId);
+ }
+
+ public void startLocked() {
+ mRouteProviderWatcher.start();
+ }
+
+ public void stopLocked() {
+ mRouteProviderWatcher.stop();
+ updateInterestLocked();
+ }
+
+ public void destroyLocked() {
+ for (int i = mSessions.size() - 1; i >= 0; i--) {
+ MediaSessionRecord session = mSessions.get(i);
+ MediaSessionService.this.destroySessionLocked(session);
+ if (session.isConnected()) {
+ session.disconnect(Session.DISCONNECT_REASON_USER_STOPPING);
+ }
+ }
+ }
+
+ public ArrayList<MediaRouteProviderProxy> getProvidersLocked() {
+ return mProviders;
+ }
+
+ public ArrayList<MediaSessionRecord> getSessionsLocked() {
+ return mSessions;
+ }
+
+ public void addSessionLocked(MediaSessionRecord session) {
+ mSessions.add(session);
+ updateInterestLocked();
+ }
+
+ public void removeSessionLocked(MediaSessionRecord session) {
+ mSessions.remove(session);
+ RouteInfo route = session.getRoute();
+ if (route != null) {
+ MediaRouteProviderProxy provider = getProviderLocked(route.getProvider());
+ if (provider != null) {
+ provider.removeSession(session);
+ }
+ }
+ updateInterestLocked();
+ }
+
+ public void dumpLocked(PrintWriter pw, String prefix) {
+ pw.println(prefix + "Record for user " + mUserId);
+ String indent = prefix + " ";
+ int size = mProviders.size();
+ pw.println(indent + size + " Providers:");
+ for (int i = 0; i < size; i++) {
+ mProviders.get(i).dump(pw, indent);
+ }
+ pw.println();
+ size = mSessions.size();
+ pw.println(indent + size + " Sessions:");
+ for (int i = 0; i < size; i++) {
+ // Just print the session info, the full session dump will
+ // already be in the list of all sessions.
+ pw.println(indent + mSessions.get(i).getSessionInfo());
+ }
+ }
+
+ public void updateInterestLocked() {
+ // TODO go through the sessions and build up the set of interfaces
+ // we're interested in. Update the provider watcher.
+ // For now, just express interest in all providers for the current
+ // user
+ boolean interested = mUserId == mCurrentUserId;
+ for (int i = mProviders.size() - 1; i >= 0; i--) {
+ mProviders.get(i).setInterested(interested);
+ }
+ }
+
+ private MediaRouteProviderProxy getProviderLocked(String providerId) {
+ for (int i = mProviders.size() - 1; i >= 0; i--) {
+ MediaRouteProviderProxy provider = mProviders.get(i);
+ if (TextUtils.equals(providerId, provider.getId())) {
+ return provider;
+ }
+ }
+ return null;
+ }
+
+ private MediaRouteProviderWatcher.Callback mProviderWatcherCallback
+ = new MediaRouteProviderWatcher.Callback() {
+ @Override
+ public void removeProvider(MediaRouteProviderProxy provider) {
+ synchronized (mLock) {
+ mProviders.remove(provider);
+ provider.setRoutesListener(null);
+ provider.setInterested(false);
+ }
+ }
+
+ @Override
+ public void addProvider(MediaRouteProviderProxy provider) {
+ synchronized (mLock) {
+ mProviders.add(provider);
+ provider.setRoutesListener(mRoutesCallback);
+ provider.setInterested(true);
+ }
+ }
+ };
+ }
+
class SessionManagerImpl extends ISessionManager.Stub {
// TODO add createSessionAsUser, pass user-id to
// ActivityManagerNative.handleIncomingUser and stash result for use
@@ -447,19 +662,19 @@ public class MediaSessionService extends SystemService implements Monitor {
if (mPrioritySession != null) {
mPrioritySession.dump(pw, "");
}
- int count = mRecords.size();
+ int count = mAllSessions.size();
pw.println(count + " Sessions:");
for (int i = 0; i < count; i++) {
- mRecords.get(i).dump(pw, "");
+ mAllSessions.get(i).dump(pw, "");
pw.println();
}
mPriorityStack.dump(pw, "");
- pw.println("Providers:");
- count = mProviders.size();
+ pw.println("User Records:");
+ count = mUserRecords.size();
for (int i = 0; i < count; i++) {
- MediaRouteProviderProxy provider = mProviders.get(i);
- provider.dump(pw, "");
+ UserRecord user = mUserRecords.get(i);
+ user.dumpLocked(pw, "");
}
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index 1e1818d..f89b14a 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -19,7 +19,6 @@ package com.android.server.media;
import android.media.session.PlaybackState;
import android.media.session.Session;
import android.os.UserHandle;
-import android.text.TextUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -49,6 +48,8 @@ public class MediaSessionStack {
private final ArrayList<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>();
+ private MediaSessionRecord mGlobalPrioritySession;
+
private MediaSessionRecord mCachedButtonReceiver;
private MediaSessionRecord mCachedDefault;
private ArrayList<MediaSessionRecord> mCachedActiveList;
@@ -61,6 +62,9 @@ public class MediaSessionStack {
*/
public void addSession(MediaSessionRecord record) {
mSessions.add(record);
+ if ((record.getFlags() & Session.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
+ mGlobalPrioritySession = record;
+ }
clearCache();
}
@@ -71,6 +75,9 @@ public class MediaSessionStack {
*/
public void removeSession(MediaSessionRecord record) {
mSessions.remove(record);
+ if (record == mGlobalPrioritySession) {
+ mGlobalPrioritySession = null;
+ }
clearCache();
}
@@ -156,6 +163,9 @@ public class MediaSessionStack {
* @return The default media button session or null.
*/
public MediaSessionRecord getDefaultMediaButtonSession(int userId) {
+ if (mGlobalPrioritySession != null && mGlobalPrioritySession.isActive()) {
+ return mGlobalPrioritySession;
+ }
if (mCachedButtonReceiver != null) {
return mCachedButtonReceiver;
}
diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
index 8cd2f9b2..b5c2730 100644
--- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
+++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
@@ -45,13 +45,13 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
private static final boolean ENABLE_PEOPLE_VALIDATOR = true;
private static final String SETTING_ENABLE_PEOPLE_VALIDATOR =
"validate_notification_people_enabled";
- private static final String[] LOOKUP_PROJECTION = { Contacts._ID };
+ private static final String[] LOOKUP_PROJECTION = { Contacts._ID, Contacts.STARRED };
private static final int MAX_PEOPLE = 10;
private static final int PEOPLE_CACHE_SIZE = 200;
private static final float NONE = 0f;
private static final float VALID_CONTACT = 0.5f;
- // TODO private static final float STARRED_CONTACT = 1f;
+ private static final float STARRED_CONTACT = 1f;
protected boolean mEnabled;
private Context mContext;
@@ -104,23 +104,29 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
public void work() {
if (INFO) Slog.i(TAG, "Executing: validation for: " + mRecord.sbn.getKey());
float affinity = NONE;
- LookupResult lookupResult = null;
for (final String handle: pendingLookups) {
+ LookupResult lookupResult = null;
final Uri uri = Uri.parse(handle);
if ("tel".equals(uri.getScheme())) {
if (DEBUG) Slog.d(TAG, "checking telephone URI: " + handle);
- lookupResult = resolvePhoneContact(handle, uri.getSchemeSpecificPart());
+ lookupResult = resolvePhoneContact(uri.getSchemeSpecificPart());
+ } else if ("mailto".equals(uri.getScheme())) {
+ if (DEBUG) Slog.d(TAG, "checking mailto URI: " + handle);
+ lookupResult = resolveEmailContact(uri.getSchemeSpecificPart());
} else if (handle.startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) {
if (DEBUG) Slog.d(TAG, "checking lookup URI: " + handle);
- lookupResult = resolveContactsUri(handle, uri);
+ lookupResult = searchContacts(uri);
} else {
+ lookupResult = new LookupResult(); // invalid person for the cache
Slog.w(TAG, "unsupported URI " + handle);
}
+ if (lookupResult != null) {
+ synchronized (mPeopleCache) {
+ mPeopleCache.put(handle, lookupResult);
+ }
+ affinity = Math.max(affinity, lookupResult.getAffinity());
+ }
}
- if (lookupResult != null) {
- affinity = Math.max(affinity, lookupResult.getAffinity());
- }
-
float affinityBound = mRecord.getContactAffinity();
affinity = Math.max(affinity, affinityBound);
mRecord.setContactAffinity(affinity);
@@ -183,47 +189,27 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
return null;
}
- private LookupResult resolvePhoneContact(final String handle, final String number) {
- LookupResult lookupResult = null;
- Cursor c = null;
- try {
- Uri numberUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
- Uri.encode(number));
- c = mContext.getContentResolver().query(numberUri, LOOKUP_PROJECTION, null, null, null);
- if (c != null && c.getCount() > 0) {
- c.moveToFirst();
- final int idIdx = c.getColumnIndex(Contacts._ID);
- final int id = c.getInt(idIdx);
- if (DEBUG) Slog.d(TAG, "is valid: " + id);
- lookupResult = new LookupResult(id);
- }
- } catch(Throwable t) {
- Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
- } finally {
- if (c != null) {
- c.close();
- }
- }
- if (lookupResult == null) {
- lookupResult = new LookupResult(LookupResult.INVALID_ID);
- }
- synchronized (mPeopleCache) {
- mPeopleCache.put(handle, lookupResult);
- }
- return lookupResult;
+ private LookupResult resolvePhoneContact(final String number) {
+ Uri phoneUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
+ Uri.encode(number));
+ return searchContacts(phoneUri);
+ }
+
+ private LookupResult resolveEmailContact(final String email) {
+ Uri numberUri = Uri.withAppendedPath(
+ ContactsContract.CommonDataKinds.Email.CONTENT_LOOKUP_URI,
+ Uri.encode(email));
+ return searchContacts(numberUri);
}
- private LookupResult resolveContactsUri(String handle, final Uri personUri) {
- LookupResult lookupResult = null;
+ private LookupResult searchContacts(Uri lookupUri) {
+ LookupResult lookupResult = new LookupResult();
Cursor c = null;
try {
- c = mContext.getContentResolver().query(personUri, LOOKUP_PROJECTION, null, null, null);
+ c = mContext.getContentResolver().query(lookupUri, LOOKUP_PROJECTION, null, null, null);
if (c != null && c.getCount() > 0) {
c.moveToFirst();
- final int idIdx = c.getColumnIndex(Contacts._ID);
- final int id = c.getInt(idIdx);
- if (DEBUG) Slog.d(TAG, "is valid: " + id);
- lookupResult = new LookupResult(id);
+ lookupResult.readContact(c);
}
} catch(Throwable t) {
Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
@@ -232,12 +218,6 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
c.close();
}
}
- if (lookupResult == null) {
- lookupResult = new LookupResult(LookupResult.INVALID_ID);
- }
- synchronized (mPeopleCache) {
- mPeopleCache.put(handle, lookupResult);
- }
return lookupResult;
}
@@ -267,12 +247,31 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
private final long mExpireMillis;
private int mId;
+ private boolean mStarred;
- public LookupResult(int id) {
- mId = id;
+ public LookupResult() {
+ mId = INVALID_ID;
+ mStarred = false;
mExpireMillis = System.currentTimeMillis() + CONTACT_REFRESH_MILLIS;
}
+ public void readContact(Cursor cursor) {
+ final int idIdx = cursor.getColumnIndex(Contacts._ID);
+ if (idIdx >= 0) {
+ mId = cursor.getInt(idIdx);
+ if (DEBUG) Slog.d(TAG, "contact _ID is: " + mId);
+ } else {
+ if (DEBUG) Slog.d(TAG, "invalid cursor: no _ID");
+ }
+ final int starIdx = cursor.getColumnIndex(Contacts.STARRED);
+ if (starIdx >= 0) {
+ mStarred = cursor.getInt(starIdx) != 0;
+ if (DEBUG) Slog.d(TAG, "contact STARRED is: " + mStarred);
+ } else {
+ if (DEBUG) Slog.d(TAG, "invalid cursor: no STARRED");
+ }
+ }
+
public boolean isExpired() {
return mExpireMillis < System.currentTimeMillis();
}
@@ -284,11 +283,18 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
public float getAffinity() {
if (isInvalid()) {
return NONE;
+ } else if (mStarred) {
+ return STARRED_CONTACT;
} else {
- return VALID_CONTACT; // TODO: finer grained result: stars
+ return VALID_CONTACT;
}
}
+ public LookupResult setStarred(boolean starred) {
+ mStarred = starred;
+ return this;
+ }
+
public LookupResult setId(int id) {
mId = id;
return this;
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 2d6cc7c..e244bde 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -190,14 +190,14 @@ final class Notifier {
+ ", workSource=" + newWorkSource);
}
try {
- mBatteryStats.noteChangeWakelockFromSource(workSource, ownerPid, tag, monitorType,
- newWorkSource, newOwnerPid, newTag, newHistoryTag,
+ mBatteryStats.noteChangeWakelockFromSource(workSource, ownerPid, tag, historyTag,
+ monitorType, newWorkSource, newOwnerPid, newTag, newHistoryTag,
newMonitorType, unimportantForLogging);
} catch (RemoteException ex) {
// Ignore
}
} else {
- onWakeLockReleased(flags, tag, packageName, ownerUid, ownerPid, workSource);
+ onWakeLockReleased(flags, tag, packageName, ownerUid, ownerPid, workSource, historyTag);
onWakeLockAcquired(newFlags, newTag, newPackageName, newOwnerUid, newOwnerPid,
newWorkSource, newHistoryTag);
}
@@ -207,7 +207,7 @@ final class Notifier {
* Called when a wake lock is released.
*/
public void onWakeLockReleased(int flags, String tag, String packageName,
- int ownerUid, int ownerPid, WorkSource workSource) {
+ int ownerUid, int ownerPid, WorkSource workSource, String historyTag) {
if (DEBUG) {
Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag
+ "\", packageName=" + packageName
@@ -218,9 +218,10 @@ final class Notifier {
try {
final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
if (workSource != null) {
- mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, monitorType);
+ mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, historyTag,
+ monitorType);
} else {
- mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, monitorType);
+ mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, historyTag, monitorType);
mAppOps.finishOperation(AppOpsManager.getToken(mAppOps),
AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 03941c6..f0b7861 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -18,6 +18,7 @@ package com.android.server.power;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
+import com.android.internal.os.BackgroundThread;
import com.android.server.BatteryService;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
@@ -400,7 +401,10 @@ public final class PowerManagerService extends com.android.server.SystemService
private long mLastWarningAboutUserActivityPermission = Long.MIN_VALUE;
// If true, the device is in low power mode.
- private static boolean mLowPowerModeEnabled;
+ private boolean mLowPowerModeEnabled;
+
+ private final ArrayList<PowerManagerInternal.LowPowerModeListener> mLowPowerModeListeners
+ = new ArrayList<PowerManagerInternal.LowPowerModeListener>();
private native void nativeInit();
@@ -623,11 +627,24 @@ public final class PowerManagerService extends com.android.server.SystemService
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT);
- boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
+ final boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
Settings.Global.LOW_POWER_MODE, 0) != 0;
if (lowPowerModeEnabled != mLowPowerModeEnabled) {
powerHintInternal(POWER_HINT_LOW_POWER_MODE, lowPowerModeEnabled ? 1 : 0);
mLowPowerModeEnabled = lowPowerModeEnabled;
+ BackgroundThread.getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ ArrayList<PowerManagerInternal.LowPowerModeListener> listeners;
+ synchronized (mLock) {
+ listeners = new ArrayList<PowerManagerInternal.LowPowerModeListener>(
+ mLowPowerModeListeners);
+ }
+ for (int i=0; i<listeners.size(); i++) {
+ listeners.get(i).onLowPowerModeChanged(lowPowerModeEnabled);
+ }
+ }
+ });
}
mDirty |= DIRTY_SETTINGS;
@@ -812,8 +829,9 @@ public final class PowerManagerService extends com.android.server.SystemService
private void notifyWakeLockReleasedLocked(WakeLock wakeLock) {
if (mSystemReady && wakeLock.mNotifiedAcquired) {
wakeLock.mNotifiedAcquired = false;
- mNotifier.onWakeLockReleased(wakeLock.mFlags, wakeLock.mTag, wakeLock.mPackageName,
- wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource);
+ mNotifier.onWakeLockReleased(wakeLock.mFlags, wakeLock.mTag,
+ wakeLock.mPackageName, wakeLock.mOwnerUid, wakeLock.mOwnerPid,
+ wakeLock.mWorkSource, wakeLock.mHistoryTag);
}
}
@@ -2972,6 +2990,20 @@ public final class PowerManagerService extends com.android.server.SystemService
}
@Override
+ public boolean getLowPowerModeEnabled() {
+ synchronized (mLock) {
+ return mLowPowerModeEnabled;
+ }
+ }
+
+ @Override
+ public void registerLowPowerModeObserver(LowPowerModeListener listener) {
+ synchronized (mLock) {
+ mLowPowerModeListeners.add(listener);
+ }
+ }
+
+ @Override
public void setPolicy(WindowManagerPolicy policy) {
PowerManagerService.this.setPolicy(policy);
}
diff --git a/services/core/java/com/android/server/wm/ViewServer.java b/services/core/java/com/android/server/wm/ViewServer.java
index a763e2c..741cee3 100644
--- a/services/core/java/com/android/server/wm/ViewServer.java
+++ b/services/core/java/com/android/server/wm/ViewServer.java
@@ -314,7 +314,7 @@ class ViewServer implements Runnable {
out.flush();
}
if (needFocusedWindowUpdate) {
- out.write("FOCUS UPDATE\n");
+ out.write("ACTION_FOCUS UPDATE\n");
out.flush();
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 836a19c..b61ba5c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2806,18 +2806,10 @@ public class WindowManagerService extends IWindowManager.Stub
boolean configChanged;
boolean surfaceChanged = false;
boolean animating;
+ boolean hasStatusBarPermission =
+ mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
+ == PackageManager.PERMISSION_GRANTED;
- // if they don't have this permission, mask out the status bar bits
- int systemUiVisibility = 0;
- if (attrs != null) {
- systemUiVisibility = (attrs.systemUiVisibility|attrs.subtreeSystemUiVisibility);
- if ((systemUiVisibility & StatusBarManager.DISABLE_MASK) != 0) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
- != PackageManager.PERMISSION_GRANTED) {
- systemUiVisibility &= ~StatusBarManager.DISABLE_MASK;
- }
- }
- }
long origId = Binder.clearCallingIdentity();
synchronized(mWindowMap) {
@@ -2832,14 +2824,26 @@ public class WindowManagerService extends IWindowManager.Stub
win.mRequestedWidth = requestedWidth;
win.mRequestedHeight = requestedHeight;
}
- if (attrs != null && seq == win.mSeq) {
- win.mSystemUiVisibility = systemUiVisibility;
- }
if (attrs != null) {
mPolicy.adjustWindowParamsLw(attrs);
}
+ // if they don't have the permission, mask out the status bar bits
+ int systemUiVisibility = 0;
+ if (attrs != null) {
+ systemUiVisibility = (attrs.systemUiVisibility|attrs.subtreeSystemUiVisibility);
+ if ((systemUiVisibility & StatusBarManager.DISABLE_MASK) != 0) {
+ if (!hasStatusBarPermission) {
+ systemUiVisibility &= ~StatusBarManager.DISABLE_MASK;
+ }
+ }
+ }
+
+ if (attrs != null && seq == win.mSeq) {
+ win.mSystemUiVisibility = systemUiVisibility;
+ }
+
winAnimator.mSurfaceDestroyDeferred =
(flags&WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY) != 0;
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
index 6e03993..1d111a1 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
@@ -142,7 +142,7 @@ private:
// Handles incoming <Request Active Source> message. If one of logical
// devices is active, it should reply with <Active Source> message.
void handleRequestActiveSource();
- void handleGetOsdName(const cec_message_t& msg);
+ void handleGiveOsdName(const cec_message_t& msg);
void handleGiveDeviceVendorID(const cec_message_t& msg);
void handleGetCECVersion(const cec_message_t& msg);
void handleGetMenuLanguage(const cec_message_t& msg);
@@ -555,8 +555,8 @@ void HdmiCecHandler::processIncomingMessage(const cec_message_t& msg) {
sendReportPhysicalAddress(msg.destination);
} else if (opcode == CEC_MESSAGE_REQUEST_ACTIVE_SOURCE) {
handleRequestActiveSource();
- } else if (opcode == CEC_MESSAGE_GET_OSD_NAME) {
- handleGetOsdName(msg);
+ } else if (opcode == CEC_MESSAGE_GIVE_OSD_NAME) {
+ handleGiveOsdName(msg);
} else if (opcode == CEC_MESSAGE_GIVE_DEVICE_VENDOR_ID) {
handleGiveDeviceVendorID(msg);
} else if (opcode == CEC_MESSAGE_GET_CEC_VERSION) {
@@ -631,7 +631,7 @@ void HdmiCecHandler::handleRequestActiveSource() {
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
-void HdmiCecHandler::handleGetOsdName(const cec_message_t& msg) {
+void HdmiCecHandler::handleGiveOsdName(const cec_message_t& msg) {
if (!mOsdName.empty()) {
sendSetOsdName(msg.destination, msg.initiator, mOsdName.c_str(), mOsdName.length());
}
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 8b54264..bcbae60 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -16,6 +16,8 @@
package com.android.server.usb;
+import android.alsa.AlsaCardsParser;
+import android.alsa.AlsaDevicesParser;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbConfiguration;
@@ -29,8 +31,6 @@ import android.os.Parcelable;
import android.os.UserHandle;
import android.util.Slog;
-import com.android.alsascan.AlsaCardsParser;
-import com.android.alsascan.AlsaDevicesParser;
import com.android.internal.annotations.GuardedBy;
import java.io.File;
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 3e9cf43..db802c5 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -216,6 +216,15 @@
</activity>
<activity
+ android:name="ClipOutlineActivity"
+ android:label="Clip/Outline">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.hwui.TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="DisplayListLayersActivity"
android:label="Layers/Display Lists">
<intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
index 1d0a806..e4ea936 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
@@ -109,26 +109,27 @@ public class CirclePropActivity extends Activity {
mToggle = !mToggle;
mRunningAnimations.add(new RenderNodeAnimator(
- mX, RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 400.0f : 200.0f));
+ mX, mToggle ? 400.0f : 200.0f));
mRunningAnimations.add(new RenderNodeAnimator(
- mY, RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 600.0f : 200.0f));
+ mY, mToggle ? 600.0f : 200.0f));
mRunningAnimations.add(new RenderNodeAnimator(
- mRadius, RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 250.0f : 150.0f));
+ mRadius, mToggle ? 250.0f : 150.0f));
mRunningAnimations.add(new RenderNodeAnimator(
mPaint, RenderNodeAnimator.PAINT_ALPHA,
- RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 64.0f : 255.0f));
+ mToggle ? 64.0f : 255.0f));
mRunningAnimations.add(new RenderNodeAnimator(
mPaint, RenderNodeAnimator.PAINT_STROKE_WIDTH,
- RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 5.0f : 60.0f));
+ mToggle ? 5.0f : 60.0f));
TimeInterpolator interp = new OvershootInterpolator(3.0f);
for (int i = 0; i < mRunningAnimations.size(); i++) {
RenderNodeAnimator anim = mRunningAnimations.get(i);
anim.setInterpolator(interp);
+ anim.setDuration(1000);
anim.start(this);
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ClipOutlineActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipOutlineActivity.java
new file mode 100644
index 0000000..af448e8
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipOutlineActivity.java
@@ -0,0 +1,87 @@
+/*
+ * 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.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Outline;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+public class ClipOutlineActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final RegionView group = new RegionView(this);
+
+ final TextView text = new TextView(this);
+ text.setText(buildText());
+ group.addView(text);
+
+ setContentView(group);
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(group, "clipPosition", 0.0f, 1.0f);
+ animator.setDuration(3000);
+ animator.setRepeatCount(ValueAnimator.INFINITE);
+ animator.setRepeatMode(ValueAnimator.REVERSE);
+ animator.start();
+ }
+
+ private static CharSequence buildText() {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < 10; i++) {
+ buffer.append(LOREM_IPSUM);
+ }
+ return buffer;
+ }
+
+ public static class RegionView extends FrameLayout {
+ private float mClipPosition = 0.0f;
+ private Outline mOutline = new Outline();
+ private Rect mRect = new Rect();
+
+ public RegionView(Context c) {
+ super(c);
+ setClipToOutline(true);
+ }
+
+ public float getClipPosition() {
+ return mClipPosition;
+ }
+
+ public void setClipPosition(float clipPosition) {
+ mClipPosition = clipPosition;
+ int w = getWidth() / 2;
+ int h = getHeight() / 2;
+
+ mRect.set(0, 0, w, h);
+ mRect.offset((int) (clipPosition * w), getHeight() / 4);
+ mOutline.setRoundRect(mRect, w / 2);
+ setOutline(mOutline);
+ invalidate();
+ }
+ }
+
+ private static final String LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sagittis molestie aliquam. Donec metus metus, laoreet nec sagittis vitae, ultricies sit amet eros. Suspendisse sed massa sit amet felis consectetur gravida. In vitae erat mi, in egestas nisl. Phasellus quis ipsum massa, at scelerisque arcu. Nam lectus est, pellentesque eget lacinia non, congue vitae augue. Aliquam erat volutpat. Pellentesque bibendum tincidunt viverra. Aliquam erat volutpat. Maecenas pretium vulputate placerat. Nulla varius elementum rutrum. Aenean mollis blandit imperdiet. Pellentesque interdum fringilla ligula.";
+}
diff --git a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
index 8f9cf58..b5b12d8 100644
--- a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
+++ b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
@@ -5,6 +5,7 @@ import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
+import android.util.Log;
import android.view.HardwareRenderer;
import android.view.RenderNodeAnimator;
import android.view.View;
@@ -73,14 +74,20 @@ public class MainActivity extends Activity implements OnItemClickListener {
float delta = (pos - clickedPosition) * 1.1f;
if (delta == 0) delta = -1;
RenderNodeAnimator animator = new RenderNodeAnimator(
- RenderNodeAnimator.TRANSLATION_Y, RenderNodeAnimator.DELTA_TYPE_DELTA, dy * delta);
+ RenderNodeAnimator.TRANSLATION_Y, dy * delta);
animator.setDuration(DURATION);
+ if (child == clickedView) logTranslationY(clickedView);
animator.start(child);
+ if (child == clickedView) logTranslationY(clickedView);
}
//mHandler.postDelayed(mLaunchActivity, (long) (DURATION * .4));
mLaunchActivity.run();
}
+ private void logTranslationY(View v) {
+ Log.d("RTTest", "View has translationY: " + v.getTranslationY());
+ }
+
private Runnable mLaunchActivity = new Runnable() {
@Override
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index dca25e5..4e0a9fe 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -453,7 +453,7 @@ String8 getComponentName(String8 &pkgName, String8 &componentName) {
return retStr;
}
-static void printCompatibleScreens(ResXMLTree& tree) {
+static void printCompatibleScreens(ResXMLTree& tree, String8* outError) {
size_t len;
ResXMLTree::event_code_t code;
int depth = 0;
@@ -471,7 +471,12 @@ static void printCompatibleScreens(ResXMLTree& tree) {
continue;
}
depth++;
- String8 tag(tree.getElementName(&len));
+ const char16_t* ctag16 = tree.getElementName(&len);
+ if (ctag16 == NULL) {
+ *outError = "failed to get XML element name (bad string pool)";
+ return;
+ }
+ String8 tag(ctag16);
if (tag == "screen") {
int32_t screenSize = getIntegerAttribute(tree,
SCREEN_SIZE_ATTR, NULL, -1);
@@ -536,7 +541,12 @@ Vector<String8> getNfcAidCategories(AssetManager& assets, String8 xmlPath, bool
while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::END_TAG) {
depth--;
- String8 tag(tree.getElementName(&len));
+ const char16_t* ctag16 = tree.getElementName(&len);
+ if (ctag16 == NULL) {
+ *outError = "failed to get XML element name (bad string pool)";
+ return Vector<String8>();
+ }
+ String8 tag(ctag16);
if (depth == 0 && tag == serviceTagName) {
withinApduService = false;
@@ -544,7 +554,12 @@ Vector<String8> getNfcAidCategories(AssetManager& assets, String8 xmlPath, bool
} else if (code == ResXMLTree::START_TAG) {
depth++;
- String8 tag(tree.getElementName(&len));
+ const char16_t* ctag16 = tree.getElementName(&len);
+ if (ctag16 == NULL) {
+ *outError = "failed to get XML element name (bad string pool)";
+ return Vector<String8>();
+ }
+ String8 tag(ctag16);
if (depth == 1) {
if (tag == serviceTagName) {
@@ -711,7 +726,12 @@ int doDump(Bundle* bundle)
continue;
}
depth++;
- String8 tag(tree.getElementName(&len));
+ const char16_t* ctag16 = tree.getElementName(&len);
+ if (ctag16 == NULL) {
+ fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
+ goto bail;
+ }
+ String8 tag(ctag16);
//printf("Depth %d tag %s\n", depth, tag.string());
if (depth == 1) {
if (tag != "manifest") {
@@ -970,7 +990,13 @@ int doDump(Bundle* bundle)
continue;
}
depth++;
- String8 tag(tree.getElementName(&len));
+
+ const char16_t* ctag16 = tree.getElementName(&len);
+ if (ctag16 == NULL) {
+ fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
+ goto bail;
+ }
+ String8 tag(ctag16);
//printf("Depth %d, %s\n", depth, tag.string());
if (depth == 1) {
if (tag != "manifest") {
@@ -1297,7 +1323,12 @@ int doDump(Bundle* bundle)
goto bail;
}
} else if (tag == "compatible-screens") {
- printCompatibleScreens(tree);
+ printCompatibleScreens(tree, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting compatible screens: %s\n",
+ error.string());
+ goto bail;
+ }
depth--;
} else if (tag == "package-verifier") {
String8 name = getAttribute(tree, NAME_ATTR, &error);
@@ -1423,7 +1454,7 @@ int doDump(Bundle* bundle)
" service '%s': %s\n", serviceName.string(), error.string());
}
} else if (bundle->getIncludeMetaData() && tag == "meta-data") {
- String8 metaDataName = getAttribute(tree, NAME_ATTR, &error);
+ String8 metaDataName = getResolvedAttribute(&res, tree, NAME_ATTR, &error);
if (error != "") {
fprintf(stderr, "ERROR getting 'android:name' attribute for "
"meta-data:%s\n", error.string());
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index aede236..56c0de9 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -757,7 +757,8 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static void native_drawRoundRect(long nativeCanvas,
- final RectF rect, final float rx, final float ry, long paint) {
+ final float left, final float top, final float right, final float bottom,
+ final float rx, final float ry, long paint) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
@@ -769,16 +770,16 @@ public final class Canvas_Delegate {
if (style == Paint.Style.FILL.nativeInt ||
style == Paint.Style.FILL_AND_STROKE.nativeInt) {
graphics.fillRoundRect(
- (int)rect.left, (int)rect.top,
- (int)rect.width(), (int)rect.height(),
+ (int)left, (int)top,
+ (int)(right - left), (int)(bottom - top),
(int)rx, (int)ry);
}
if (style == Paint.Style.STROKE.nativeInt ||
style == Paint.Style.FILL_AND_STROKE.nativeInt) {
graphics.drawRoundRect(
- (int)rect.left, (int)rect.top,
- (int)rect.width(), (int)rect.height(),
+ (int)left, (int)top,
+ (int)(right - left), (int)(bottom - top),
(int)rx, (int)ry);
}
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 25eaaf5..83df745 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -420,7 +420,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void nSetShadowLayer(Paint thisPaint, float radius, float dx, float dy,
+ /*package*/ static void native_setShadowLayer(long paint, float radius, float dx, float dy,
int color) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -428,6 +428,14 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
+ /*package*/ static boolean native_hasShadowLayer(long paint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Paint.hasShadowLayer is not supported.", null, null /*data*/);
+ return false;
+ }
+
+ @LayoutlibDelegate
/*package*/ static boolean isElegantTextHeight(Paint thisPaint) {
return false;
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index b235408..0ec7115 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -318,16 +318,6 @@ public final class Path_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_addRect(long nPath, RectF rect, int dir) {
- Path_Delegate pathDelegate = sManager.getDelegate(nPath);
- if (pathDelegate == null) {
- return;
- }
-
- pathDelegate.addRect(rect.left, rect.top, rect.right, rect.bottom, dir);
- }
-
- @LayoutlibDelegate
/*package*/ static void native_addRect(long nPath,
float left, float top, float right, float bottom, int dir) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
@@ -339,14 +329,15 @@ public final class Path_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_addOval(long nPath, RectF oval, int dir) {
+ /*package*/ static void native_addOval(long nPath, float left, float top, float right,
+ float bottom, int dir) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
pathDelegate.mPath.append(new Ellipse2D.Float(
- oval.left, oval.top, oval.width(), oval.height()), false);
+ left, top, right - left, bottom - top), false);
}
@LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/os/Build_Delegate.java b/tools/layoutlib/bridge/src/android/os/SystemProperties_Delegate.java
index ff82a5e..1e7564e 100644
--- a/tools/layoutlib/bridge/src/android/os/Build_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/os/SystemProperties_Delegate.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * 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.
@@ -23,26 +23,29 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.util.Map;
/**
- * Delegate implementing the native methods of android.os.Build
+ * Delegate implementing the native methods of android.os.SystemProperties
*
- * Through the layoutlib_create tool, the original native methods of Build have been replaced
- * by calls to methods of the same name in this delegate class.
+ * Through the layoutlib_create tool, the original native methods of SystemProperties have been
+ * replaced by calls to methods of the same name in this delegate class.
*
* Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
* around to map int to instance of the delegate.
- *
*/
-public class Build_Delegate {
+public class SystemProperties_Delegate {
@LayoutlibDelegate
- /*package*/ static String getString(String property) {
+ /*package*/ static String native_get(String key) {
+ return native_get(key, "");
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String native_get(String key, String def) {
Map<String, String> properties = Bridge.getPlatformProperties();
- String value = properties.get(property);
+ String value = properties.get(key);
if (value != null) {
return value;
}
- return Build.UNKNOWN;
+ return def;
}
-
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 59979ce..bb72a1e 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -133,7 +133,6 @@ public final class CreateInfo implements ICreateInfo {
"android.graphics.BitmapFactory#finishDecode",
"android.os.Handler#sendMessageAtTime",
"android.os.HandlerThread#run",
- "android.os.Build#getString",
"android.text.format.DateFormat#is24HourFormat",
"android.view.Choreographer#getRefreshRate",
"android.view.Display#updateDisplayInfoLocked",
@@ -148,6 +147,7 @@ public final class CreateInfo implements ICreateInfo {
"com.android.internal.view.menu.MenuBuilder#createNewMenuItem",
"com.android.internal.util.XmlUtils#convertValueToInt",
"com.android.internal.textservice.ITextServicesManager$Stub#asInterface",
+ "android.os.SystemProperties#native_get",
};
/**
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 85b81d9..e73cce1 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -417,6 +417,12 @@ public class WifiConfiguration implements Parcelable {
public int autoJoinStatus;
/**
+ * Set if the configuration was self added by the framework
+ * @hide
+ */
+ public boolean selfAdded;
+
+ /**
* @hide
* Indicate that a WifiConfiguration is temporary and should not be saved
* nor considered by AutoJoin.
@@ -498,6 +504,8 @@ public class WifiConfiguration implements Parcelable {
proxySettings = ProxySettings.UNASSIGNED;
linkProperties = new LinkProperties();
autoJoinStatus = AUTO_JOIN_ENABLED;
+ selfAdded = false;
+ ephemeral = false;
}
/**
@@ -794,8 +802,28 @@ public class WifiConfiguration implements Parcelable {
return configKey(false);
}
+ /** @hide
+ * return the config key string based on a scan result
+ */
+ static public String configKey(ScanResult result) {
+ String key = "\"" + result.SSID + "\"";
+
+ if (result.capabilities.contains("WEP")) {
+ key = key + "-WEP";
+ }
- /** Implement the Parcelable interface {@hide} */
+ if (result.capabilities.contains("PSK")) {
+ key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_PSK];
+ }
+
+ if (result.capabilities.contains("EAP")) {
+ key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_EAP];
+ }
+
+ return key;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
public int describeContents() {
return 0;
}
@@ -849,6 +877,7 @@ public class WifiConfiguration implements Parcelable {
}
mCachedConfigKey = null; //force null configKey
autoJoinStatus = source.autoJoinStatus;
+ selfAdded = source.selfAdded;
if (source.visibility != null) {
visibility = new Visibility(source.visibility);
@@ -886,6 +915,7 @@ public class WifiConfiguration implements Parcelable {
dest.writeString(dhcpServer);
dest.writeString(defaultGwMacAddress);
dest.writeInt(autoJoinStatus);
+ dest.writeInt(selfAdded ? 1 : 0);
}
/** Implement the Parcelable interface {@hide} */
@@ -920,7 +950,7 @@ public class WifiConfiguration implements Parcelable {
config.dhcpServer = in.readString();
config.defaultGwMacAddress = in.readString();
config.autoJoinStatus = in.readInt();
-
+ config.selfAdded = in.readInt() != 0;
return config;
}