summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt110
-rw-r--r--core/java/android/app/Activity.java6
-rw-r--r--core/java/android/app/DatePickerDialog.java9
-rw-r--r--core/java/android/app/ExitTransitionCoordinator.java4
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java4
-rw-r--r--core/java/android/app/job/JobInfo.java5
-rw-r--r--core/java/android/bluetooth/le/BluetoothLeAdvertiser.java10
-rw-r--r--core/java/android/bluetooth/le/BluetoothLeScanner.java11
-rw-r--r--core/java/android/content/res/ColorStateList.java40
-rw-r--r--core/java/android/content/res/TypedArray.java36
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java2
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java3
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java26
-rw-r--r--core/java/android/hardware/camera2/TotalCaptureResult.java6
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java21
-rw-r--r--core/java/android/hardware/camera2/legacy/CaptureCollector.java66
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java301
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java109
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java56
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyResultMapper.java93
-rw-r--r--core/java/android/hardware/camera2/legacy/RequestThreadManager.java33
-rw-r--r--core/java/android/hardware/camera2/utils/ArrayUtils.java59
-rw-r--r--core/java/android/hardware/camera2/utils/ParamsUtils.java19
-rw-r--r--core/java/android/hardware/display/DisplayManager.java4
-rw-r--r--core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java50
-rw-r--r--core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl4
-rw-r--r--core/java/android/hardware/soundtrigger/SoundTrigger.aidl2
-rw-r--r--core/java/android/hardware/soundtrigger/SoundTrigger.java167
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java11
-rw-r--r--core/java/android/view/View.java19
-rw-r--r--core/java/android/view/ViewDebug.java181
-rw-r--r--core/java/android/view/ViewGroup.java4
-rw-r--r--core/java/android/view/WindowManager.java2
-rw-r--r--core/java/android/widget/DatePicker.java349
-rw-r--r--core/java/android/widget/DatePickerDelegate.java261
-rw-r--r--core/java/android/widget/LinearLayout.java2
-rw-r--r--core/java/android/widget/RadialTimePickerView.java19
-rw-r--r--core/java/android/widget/TextViewWithCircularIndicator.java8
-rw-r--r--core/java/android/widget/TimePickerDelegate.java78
-rw-r--r--core/java/android/widget/YearPickerView.java16
-rw-r--r--core/jni/android/graphics/MinikinUtils.cpp36
-rw-r--r--core/res/res/color/date_picker_calendar_material_dark.xml25
-rw-r--r--core/res/res/color/date_picker_calendar_material_light.xml25
-rw-r--r--core/res/res/color/date_picker_selector_material_dark.xml25
-rw-r--r--core/res/res/color/date_picker_selector_material_light.xml25
-rw-r--r--core/res/res/color/date_picker_year_selector_material_dark.xml23
-rw-r--r--core/res/res/color/date_picker_year_selector_material_light.xml23
-rw-r--r--core/res/res/layout-land/date_picker_holo.xml1
-rw-r--r--core/res/res/layout/date_picker_header_view.xml5
-rw-r--r--core/res/res/layout/date_picker_holo.xml6
-rw-r--r--core/res/res/layout/date_picker_selected_date.xml16
-rw-r--r--core/res/res/layout/year_label_text_view.xml3
-rw-r--r--core/res/res/values-television/themes.xml5
-rw-r--r--core/res/res/values-television/themes_device_defaults.xml2
-rw-r--r--core/res/res/values/attrs.xml87
-rw-r--r--core/res/res/values/public.xml23
-rw-r--r--core/res/res/values/styles.xml30
-rw-r--r--core/res/res/values/styles_device_defaults.xml25
-rw-r--r--core/res/res/values/styles_holo.xml44
-rw-r--r--core/res/res/values/styles_leanback.xml4
-rw-r--r--core/res/res/values/styles_material.xml90
-rw-r--r--core/res/res/values/symbols.xml17
-rw-r--r--core/res/res/values/themes.xml46
-rw-r--r--core/res/res/values/themes_device_defaults.xml40
-rw-r--r--core/res/res/values/themes_holo.xml80
-rw-r--r--core/res/res/values/themes_leanback.xml18
-rw-r--r--core/res/res/values/themes_material.xml83
-rw-r--r--docs/html/images/tools/as-allocstart.pngbin0 -> 590 bytes
-rw-r--r--docs/html/images/tools/as-allocstop.pngbin0 -> 684 bytes
-rw-r--r--docs/html/images/tools/as-alloctrack.pngbin0 -> 49699 bytes
-rw-r--r--docs/html/sdk/installing/studio-debug.jd42
-rw-r--r--docs/html/training/wearables/apps/creating.jd2
-rw-r--r--docs/html/training/wearables/apps/packaging.jd4
-rw-r--r--docs/html/training/wearables/apps/voice.jd4
-rw-r--r--docs/html/training/wearables/data-layer/events.jd6
-rw-r--r--docs/html/training/wearables/data-layer/messages.jd2
-rw-r--r--docs/html/training/wearables/notifications/creating.jd14
-rw-r--r--graphics/java/android/graphics/drawable/RippleDrawable.java25
-rw-r--r--libs/androidfw/ResourceTypes.cpp21
-rw-r--r--libs/hwui/Debug.h3
-rw-r--r--libs/hwui/Layer.cpp2
-rw-r--r--libs/hwui/LayerRenderer.cpp3
-rwxr-xr-xlibs/hwui/OpenGLRenderer.cpp54
-rwxr-xr-xlibs/hwui/OpenGLRenderer.h5
-rw-r--r--libs/hwui/Rect.h2
-rw-r--r--libs/hwui/StatefulBaseRenderer.cpp1
-rw-r--r--libs/hwui/TextureCache.cpp3
-rw-r--r--media/java/android/media/AudioAttributes.java1
-rw-r--r--media/java/android/media/AudioManager.java6
-rw-r--r--media/java/android/media/AudioPortEventHandler.java6
-rw-r--r--media/java/android/media/AudioService.java12
-rw-r--r--media/java/android/media/MediaFormat.java3
-rw-r--r--media/java/android/media/MediaPlayer.java133
-rw-r--r--media/java/android/media/SRTRenderer.java202
-rw-r--r--media/java/android/media/SubtitleController.java13
-rw-r--r--media/java/android/media/SubtitleTrack.java16
-rw-r--r--media/java/android/media/WebVttRenderer.java4
-rw-r--r--media/java/android/media/projection/MediaProjection.java3
-rw-r--r--media/jni/android_media_MediaPlayer.cpp2
-rw-r--r--packages/SystemUI/src/com/android/systemui/ExpandHelper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java10
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java11
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java546
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java22
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java22
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java6
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java10
-rw-r--r--services/core/java/com/android/server/job/JobServiceContext.java104
-rw-r--r--services/core/java/com/android/server/tv/TvInputHardwareManager.java19
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java74
-rw-r--r--telecomm/java/android/telecomm/Connection.java16
-rw-r--r--telecomm/java/android/telecomm/ConnectionRequest.java8
-rw-r--r--telecomm/java/android/telecomm/ConnectionService.java123
-rw-r--r--telecomm/java/android/telecomm/InCallAdapter.java24
-rw-r--r--telecomm/java/android/telecomm/Phone.java23
-rw-r--r--telecomm/java/android/telecomm/PhoneAccount.java37
-rw-r--r--telecomm/java/android/telecomm/RemoteConnectionManager.java4
-rw-r--r--telecomm/java/android/telecomm/RemoteConnectionService.java12
-rw-r--r--telecomm/java/android/telecomm/TelecommManager.java8
-rw-r--r--telecomm/java/android/telecomm/VideoCallProfile.java127
-rw-r--r--telecomm/java/com/android/internal/telecomm/IConnectionService.aidl6
-rw-r--r--telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl4
-rw-r--r--telephony/java/com/android/ims/ImsCallProfile.java20
-rw-r--r--tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java60
-rw-r--r--tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java77
-rw-r--r--tests/UsesFeature2Test/AndroidManifest.xml1
-rw-r--r--tools/aapt/Command.cpp54
-rw-r--r--wifi/java/android/net/wifi/WifiConnectionStatistics.java19
129 files changed, 2730 insertions, 2340 deletions
diff --git a/api/current.txt b/api/current.txt
index a4a4a09..046056a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -326,9 +326,8 @@ package android {
field public static final int alphabeticShortcut = 16843235; // 0x10101e3
field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef
field public static final int alwaysRetainTaskState = 16843267; // 0x1010203
- field public static final int amPmSelectedBackgroundColor = 16843947; // 0x10104ab
- field public static final int amPmTextColor = 16843945; // 0x10104a9
- field public static final int amPmUnselectedBackgroundColor = 16843946; // 0x10104aa
+ field public static final int amPmBackgroundColor = 16843944; // 0x10104a8
+ field public static final int amPmTextColor = 16843943; // 0x10104a7
field public static final int angle = 16843168; // 0x10101a0
field public static final int animateFirstView = 16843477; // 0x10102d5
field public static final int animateLayoutChanges = 16843506; // 0x10102f2
@@ -389,7 +388,7 @@ package android {
field public static final int buttonTint = 16843889; // 0x1010471
field public static final int buttonTintMode = 16843890; // 0x1010472
field public static final int cacheColorHint = 16843009; // 0x1010101
- field public static final int calendarTextColor = 16843934; // 0x101049e
+ field public static final int calendarTextColor = 16843933; // 0x101049d
field public static final int calendarViewShown = 16843596; // 0x101034c
field public static final int calendarViewStyle = 16843613; // 0x101035d
field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
@@ -407,8 +406,8 @@ package android {
field public static final int centerY = 16843171; // 0x10101a3
field public static final int checkBoxPreferenceStyle = 16842895; // 0x101008f
field public static final int checkMark = 16843016; // 0x1010108
- field public static final int checkMarkTint = 16843949; // 0x10104ad
- field public static final int checkMarkTintMode = 16843950; // 0x10104ae
+ field public static final int checkMarkTint = 16843946; // 0x10104aa
+ field public static final int checkMarkTintMode = 16843947; // 0x10104ab
field public static final int checkable = 16843237; // 0x10101e5
field public static final int checkableBehavior = 16843232; // 0x10101e0
field public static final int checkboxStyle = 16842860; // 0x101006c
@@ -479,16 +478,11 @@ package android {
field public static final int dashGap = 16843175; // 0x10101a7
field public static final int dashWidth = 16843174; // 0x10101a6
field public static final int data = 16842798; // 0x101002e
+ field public static final int datePickerDialogTheme = 16843951; // 0x10104af
field public static final int datePickerStyle = 16843612; // 0x101035c
- field public static final int dateSelectorBackgroundColor = 16843928; // 0x1010498
- field public static final int dateSelectorDayOfMonthTextAppearance = 16843930; // 0x101049a
- field public static final int dateSelectorDayOfWeekBackgroundColor = 16843926; // 0x1010496
- field public static final int dateSelectorDayOfWeekTextAppearance = 16843927; // 0x1010497
- field public static final int dateSelectorMonthTextAppearance = 16843929; // 0x1010499
- field public static final int dateSelectorYearListItemTextAppearance = 16843932; // 0x101049c
- field public static final int dateSelectorYearListSelectedCircleColor = 16843933; // 0x101049d
- field public static final int dateSelectorYearTextAppearance = 16843931; // 0x101049b
field public static final int dateTextAppearance = 16843593; // 0x1010349
+ field public static final int dayOfWeekBackgroundColor = 16843926; // 0x1010496
+ field public static final int dayOfWeekTextAppearance = 16843927; // 0x1010497
field public static final int debuggable = 16842767; // 0x101000f
field public static final int defaultValue = 16843245; // 0x10101ed
field public static final int delay = 16843212; // 0x10101cc
@@ -658,12 +652,14 @@ package android {
field public static final int hapticFeedbackEnabled = 16843358; // 0x101025e
field public static final int hardwareAccelerated = 16843475; // 0x10102d3
field public static final int hasCode = 16842764; // 0x101000c
- field public static final int headerAmPmTextAppearance = 16843939; // 0x10104a3
+ field public static final int headerAmPmTextAppearance = 16843938; // 0x10104a2
field public static final int headerBackground = 16843055; // 0x101012f
- field public static final int headerBackgroundColor = 16843941; // 0x10104a5
+ field public static final int headerBackgroundColor = 16843939; // 0x10104a3
+ field public static final int headerDayOfMonthTextAppearance = 16843929; // 0x1010499
field public static final int headerDividersEnabled = 16843310; // 0x101022e
- field public static final int headerSelectedTextColor = 16843940; // 0x10104a4
- field public static final int headerTimeTextAppearance = 16843938; // 0x10104a2
+ field public static final int headerMonthTextAppearance = 16843928; // 0x1010498
+ field public static final int headerTimeTextAppearance = 16843937; // 0x10104a1
+ field public static final int headerYearTextAppearance = 16843930; // 0x101049a
field public static final int height = 16843093; // 0x1010155
field public static final int hideOnContentScroll = 16843845; // 0x1010445
field public static final int hint = 16843088; // 0x1010150
@@ -919,9 +915,9 @@ package android {
field public static final int notificationTimeout = 16843651; // 0x1010383
field public static final int numColumns = 16843032; // 0x1010118
field public static final int numStars = 16843076; // 0x1010144
- field public static final int numbersBackgroundColor = 16843943; // 0x10104a7
- field public static final int numbersSelectorColor = 16843944; // 0x10104a8
- field public static final int numbersTextColor = 16843942; // 0x10104a6
+ field public static final int numbersBackgroundColor = 16843941; // 0x10104a5
+ field public static final int numbersSelectorColor = 16843942; // 0x10104a6
+ field public static final int numbersTextColor = 16843940; // 0x10104a4
field public static final deprecated int numeric = 16843109; // 0x1010165
field public static final int numericShortcut = 16843236; // 0x10101e4
field public static final int onClick = 16843375; // 0x101026f
@@ -975,7 +971,7 @@ package android {
field public static final int popupKeyboard = 16843331; // 0x1010243
field public static final int popupLayout = 16843323; // 0x101023b
field public static final int popupMenuStyle = 16843520; // 0x1010300
- field public static final int popupTheme = 16843951; // 0x10104af
+ field public static final int popupTheme = 16843948; // 0x10104ac
field public static final int popupWindowStyle = 16842870; // 0x1010076
field public static final int port = 16842793; // 0x1010029
field public static final int positiveButtonText = 16843253; // 0x10101f5
@@ -1027,7 +1023,7 @@ package android {
field public static final int ratingBarStyleIndicator = 16843280; // 0x1010210
field public static final int ratingBarStyleSmall = 16842877; // 0x101007d
field public static final int readPermission = 16842759; // 0x1010007
- field public static final int recognitionService = 16843935; // 0x101049f
+ field public static final int recognitionService = 16843934; // 0x101049e
field public static final int relinquishTaskIdentity = 16843896; // 0x1010478
field public static final int repeatCount = 16843199; // 0x10101bf
field public static final int repeatMode = 16843200; // 0x10101c0
@@ -1314,8 +1310,8 @@ package android {
field public static final int tileMode = 16843265; // 0x1010201
field public static final int tileModeX = 16843897; // 0x1010479
field public static final int tileModeY = 16843898; // 0x101047a
- field public static final int timePickerDialogTheme = 16843937; // 0x10104a1
- field public static final int timePickerStyle = 16843936; // 0x10104a0
+ field public static final int timePickerDialogTheme = 16843936; // 0x10104a0
+ field public static final int timePickerStyle = 16843935; // 0x101049f
field public static final int timeZone = 16843724; // 0x10103cc
field public static final int tint = 16843041; // 0x1010121
field public static final int tintMode = 16843797; // 0x1010415
@@ -1331,7 +1327,7 @@ package android {
field public static final int toXScale = 16843203; // 0x10101c3
field public static final int toYDelta = 16843209; // 0x10101c9
field public static final int toYScale = 16843205; // 0x10101c5
- field public static final int toolbarStyle = 16843952; // 0x10104b0
+ field public static final int toolbarStyle = 16843949; // 0x10104ad
field public static final int top = 16843182; // 0x10101ae
field public static final int topBright = 16842955; // 0x10100cb
field public static final int topDark = 16842951; // 0x10100c7
@@ -1415,7 +1411,7 @@ package android {
field public static final int windowAllowExitTransitionOverlap = 16843837; // 0x101043d
field public static final int windowAnimationStyle = 16842926; // 0x10100ae
field public static final int windowBackground = 16842836; // 0x1010054
- field public static final int windowClipToOutline = 16843953; // 0x10104b1
+ field public static final int windowClipToOutline = 16843950; // 0x10104ae
field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
field public static final int windowContentOverlay = 16842841; // 0x1010059
field public static final int windowContentTransitionManager = 16843795; // 0x1010413
@@ -1454,6 +1450,8 @@ package android {
field public static final int x = 16842924; // 0x10100ac
field public static final int xlargeScreens = 16843455; // 0x10102bf
field public static final int y = 16842925; // 0x10100ad
+ field public static final int yearListItemTextAppearance = 16843931; // 0x101049b
+ field public static final int yearListSelectorColor = 16843932; // 0x101049c
field public static final int yesNoPreferenceStyle = 16842896; // 0x1010090
field public static final int zAdjustment = 16843201; // 0x10101c1
}
@@ -5384,7 +5382,6 @@ package android.app.admin {
method public android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
method public void enableSystemApp(android.content.ComponentName, java.lang.String);
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
- method public void setTrustAgentFeaturesEnabled(android.content.ComponentName, android.content.ComponentName, java.util.List<java.lang.String>);
method public java.lang.String[] getAccountTypesWithManagementDisabled();
method public java.util.List<android.content.ComponentName> getActiveAdmins();
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
@@ -5456,6 +5453,7 @@ package android.app.admin {
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public int setStorageEncryption(android.content.ComponentName, boolean);
+ method public void setTrustAgentFeaturesEnabled(android.content.ComponentName, android.content.ComponentName, java.util.List<java.lang.String>);
method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
method public void uninstallCaCert(android.content.ComponentName, byte[]);
method public void wipeData(int);
@@ -13031,7 +13029,7 @@ package android.hardware.camera2 {
public class CaptureResult extends android.hardware.camera2.CameraMetadata {
method public T get(android.hardware.camera2.CaptureResult.Key<T>);
- method public int getFrameNumber();
+ method public long getFrameNumber();
method public android.hardware.camera2.CaptureRequest getRequest();
method public int getSequenceId();
field public static final android.hardware.camera2.CaptureResult.Key BLACK_LEVEL_LOCK;
@@ -13077,7 +13075,6 @@ package android.hardware.camera2 {
field public static final android.hardware.camera2.CaptureResult.Key LENS_OPTICAL_STABILIZATION_MODE;
field public static final android.hardware.camera2.CaptureResult.Key LENS_STATE;
field public static final android.hardware.camera2.CaptureResult.Key NOISE_REDUCTION_MODE;
- field public static final android.hardware.camera2.CaptureResult.Key REQUEST_FRAME_COUNT;
field public static final android.hardware.camera2.CaptureResult.Key REQUEST_PIPELINE_DEPTH;
field public static final android.hardware.camera2.CaptureResult.Key SCALER_CROP_REGION;
field public static final android.hardware.camera2.CaptureResult.Key SENSOR_EXPOSURE_TIME;
@@ -28731,15 +28728,15 @@ package android.telecomm {
public abstract class ConnectionService extends android.app.Service {
ctor public ConnectionService();
- method public final android.telecomm.RemoteConnection createRemoteIncomingConnection(android.telecomm.ConnectionRequest);
- method public final android.telecomm.RemoteConnection createRemoteOutgoingConnection(android.telecomm.ConnectionRequest);
+ method public final android.telecomm.RemoteConnection createRemoteIncomingConnection(android.telecomm.PhoneAccountHandle, android.telecomm.ConnectionRequest);
+ method public final android.telecomm.RemoteConnection createRemoteOutgoingConnection(android.telecomm.PhoneAccountHandle, android.telecomm.ConnectionRequest);
method public final java.util.Collection<android.telecomm.Connection> getAllConnections();
method public final android.os.IBinder onBind(android.content.Intent);
method public void onConnectionAdded(android.telecomm.Connection);
method public void onConnectionRemoved(android.telecomm.Connection);
method public void onCreateConferenceConnection(java.lang.String, android.telecomm.Connection, android.telecomm.Response<java.lang.String, android.telecomm.Connection>);
- method public android.telecomm.Connection onCreateIncomingConnection(android.telecomm.ConnectionRequest);
- method public android.telecomm.Connection onCreateOutgoingConnection(android.telecomm.ConnectionRequest);
+ method public android.telecomm.Connection onCreateIncomingConnection(android.telecomm.PhoneAccountHandle, android.telecomm.ConnectionRequest);
+ method public android.telecomm.Connection onCreateOutgoingConnection(android.telecomm.PhoneAccountHandle, android.telecomm.ConnectionRequest);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecomm.ConnectionService";
}
@@ -28792,6 +28789,8 @@ package android.telecomm {
method public void setAudioRoute(int);
method public void stopDtmfTone(java.lang.String);
method public void swapWithBackgroundCall(java.lang.String);
+ method public void turnProximitySensorOff(boolean);
+ method public void turnProximitySensorOn();
method public void unholdCall(java.lang.String);
}
@@ -28842,6 +28841,8 @@ package android.telecomm {
method public final void removeListener(android.telecomm.Phone.Listener);
method public final void setAudioRoute(int);
method public final void setMuted(boolean);
+ method public final void setProximitySensorOff(boolean);
+ method public final void setProximitySensorOn();
}
public static abstract class Phone.Listener {
@@ -28853,7 +28854,7 @@ package android.telecomm {
}
public class PhoneAccount implements android.os.Parcelable {
- ctor public PhoneAccount(android.telecomm.PhoneAccountHandle, android.net.Uri, java.lang.String, int, int, java.lang.CharSequence, java.lang.CharSequence, boolean);
+ ctor public PhoneAccount(android.telecomm.PhoneAccountHandle, android.net.Uri, java.lang.String, int, int, java.lang.CharSequence, java.lang.CharSequence);
method public int describeContents();
method public android.telecomm.PhoneAccountHandle getAccountHandle();
method public int getCapabilities();
@@ -28863,10 +28864,10 @@ package android.telecomm {
method public java.lang.CharSequence getLabel();
method public java.lang.CharSequence getShortDescription();
method public java.lang.String getSubscriptionNumber();
- method public boolean isVideoCallingSupported();
method public void writeToParcel(android.os.Parcel, int);
- field public static final int CAPABILITY_SIM_CALL_MANAGER = 1; // 0x1
+ field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
+ field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
field public static final android.os.Parcelable.Creator CREATOR;
}
@@ -28994,11 +28995,20 @@ package android.telecomm {
field public static final int QUALITY_HIGH = 1; // 0x1
field public static final int QUALITY_LOW = 3; // 0x3
field public static final int QUALITY_MEDIUM = 2; // 0x2
- field public static final int VIDEO_STATE_AUDIO_ONLY = 0; // 0x0
- field public static final int VIDEO_STATE_BIDIRECTIONAL = 3; // 0x3
- field public static final int VIDEO_STATE_PAUSED = 4; // 0x4
- field public static final int VIDEO_STATE_RX_ENABLED = 2; // 0x2
- field public static final int VIDEO_STATE_TX_ENABLED = 1; // 0x1
+ }
+
+ public static class VideoCallProfile.VideoState {
+ ctor public VideoCallProfile.VideoState();
+ method public static boolean isAudioOnly(int);
+ method public static boolean isPaused(int);
+ method public static boolean isReceptionEnabled(int);
+ method public static boolean isBidirectional(int);
+ method public static boolean isTransmissionEnabled(int);
+ field public static final int AUDIO_ONLY = 0; // 0x0
+ field public static final int BIDIRECTIONAL = 3; // 0x3
+ field public static final int PAUSED = 4; // 0x4
+ field public static final int RX_ENABLED = 2; // 0x2
+ field public static final int TX_ENABLED = 1; // 0x1
}
}
@@ -38013,16 +38023,8 @@ package android.widget {
ctor public DatePicker(android.content.Context, android.util.AttributeSet);
ctor public DatePicker(android.content.Context, android.util.AttributeSet, int);
ctor public DatePicker(android.content.Context, android.util.AttributeSet, int, int);
- method public android.content.res.ColorStateList getCalendarTextColor();
method public android.widget.CalendarView getCalendarView();
method public boolean getCalendarViewShown();
- method public int getDateSelectorBackgroundColor();
- method public int getDateSelectorDayOfMonthTextAppearance();
- method public int getDateSelectorDayOfWeekBackgroundColor();
- method public int getDateSelectorDayOfWeekTextAppearance();
- method public int getDateSelectorMonthTextAppearance();
- method public int getDateSelectorYearListItemTextAppearance();
- method public int getDateSelectorYearTextAppearance();
method public int getDayOfMonth();
method public long getMaxDate();
method public long getMinDate();
@@ -38030,15 +38032,7 @@ package android.widget {
method public boolean getSpinnersShown();
method public int getYear();
method public void init(int, int, int, android.widget.DatePicker.OnDateChangedListener);
- method public void setCalendarTextColor(android.content.res.ColorStateList);
method public void setCalendarViewShown(boolean);
- method public void setDateSelectorBackgroundColor(int);
- method public void setDateSelectorDayOfMonthTextAppearance(int);
- method public void setDateSelectorDayOfWeekBackgroundColor(int);
- method public void setDateSelectorDayOfWeekTextAppearance(int);
- method public void setDateSelectorMonthTextAppearance(int);
- method public void setDateSelectorYearListItemTextAppearance(int);
- method public void setDateSelectorYearTextAppearance(int);
method public void setMaxDate(long);
method public void setMinDate(long);
method public void setSpinnersShown(boolean);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 394175a..fcfeddd 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -6077,9 +6077,9 @@ public class Activity extends ContextThemeWrapper
*
* If {@link DevicePolicyManager#isLockTaskPermitted(String)} returns false
* then the system will prompt the user with a dialog requesting permission to enter
- * this mode. When entered through this method the user can exit at any time by
- * swiping down twice from the top of the screen. Calling stopLockTask will also
- * exit the mode.
+ * this mode. When entered through this method the user can exit at any time through
+ * an action described by the request dialog. Calling stopLockTask will also exit the
+ * mode.
*/
public void startLockTask() {
try {
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index d7fb707..a78b137 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -112,15 +112,14 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
Context themeContext = getContext();
- LayoutInflater inflater =
- (LayoutInflater) themeContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- View view = inflater.inflate(R.layout.date_picker_dialog, null);
+ final LayoutInflater inflater = (LayoutInflater) themeContext.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ final View view = inflater.inflate(R.layout.date_picker_dialog, null);
setView(view);
setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
- mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
// Initialize state
- mDatePicker.setLegacyMode(false, null);
+ mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
mDatePicker.setShowDoneButton(true);
mDatePicker.setDismissCallback(new DatePicker.DatePickerDismissCallback() {
@Override
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index f4eb558..2ce6018 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -117,7 +117,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
setTransitionAlpha(mTransitioningViews, 1);
setTransitionAlpha(mSharedElements, 1);
mIsHidden = true;
- if (getDecor() != null) {
+ if (!mIsReturning && getDecor() != null) {
getDecor().suppressLayout(false);
}
clearState();
@@ -357,7 +357,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
mExitNotified = true;
mResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null);
mResultReceiver = null; // done talking
- if (getDecor() != null) {
+ if (!mIsReturning && getDecor() != null) {
getDecor().suppressLayout(false);
}
finishIfNecessary();
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index b84eca2..0e6f86e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2328,7 +2328,7 @@ public class DevicePolicyManager {
}
/**
- * Sets a list of features to enable for a TrustAgentService component. This is meant to be
+ * Sets a list of features to enable for a TrustAgent component. This is meant to be
* used in conjunction with {@link #KEYGUARD_DISABLE_TRUST_AGENTS}, which will disable all
* trust agents but those with features enabled by this function call.
*
@@ -2353,7 +2353,7 @@ public class DevicePolicyManager {
}
/**
- * Gets list of enabled features for the given {@link TrustAgentService} agent. If admin is
+ * Gets list of enabled features for the given TrustAgent component. If admin is
* null, this will return the intersection of all features enabled for the given agent by all
* admins.
*
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 70f6966..936e205 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -266,6 +266,11 @@ public class JobInfo implements Parcelable {
}
};
+ @Override
+ public String toString() {
+ return "(job:" + jobId + "/" + service.flattenToShortString() + ")";
+ }
+
/** Builder class for constructing {@link JobInfo} objects. */
public static final class Builder {
private int mJobId;
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 93d4349..4d128e7 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -107,6 +107,7 @@ public final class BluetoothLeAdvertiser {
public void startAdvertising(AdvertiseSettings settings,
AdvertiseData advertiseData, AdvertiseData scanResponse,
final AdvertiseCallback callback) {
+ checkAdapterState();
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
}
@@ -153,13 +154,13 @@ public final class BluetoothLeAdvertiser {
* @param callback {@link AdvertiseCallback} identifies the advertising instance to stop.
*/
public void stopAdvertising(final AdvertiseCallback callback) {
+ checkAdapterState();
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
}
AdvertiseCallbackWrapper wrapper = mLeAdvertisers.get(callback);
if (wrapper == null)
return;
-
try {
IBluetoothGatt gatt = mBluetoothManager.getBluetoothGatt();
if (gatt != null)
@@ -459,6 +460,13 @@ public final class BluetoothLeAdvertiser {
}
}
+ //TODO: move this api to a common util class.
+ private void checkAdapterState() {
+ if (mBluetoothAdapter.getState() != mBluetoothAdapter.STATE_ON) {
+ throw new IllegalStateException("BT Adapter is not turned ON");
+ }
+ }
+
private void postCallbackFailure(final AdvertiseCallback callback, final int error) {
mHandler.post(new Runnable() {
@Override
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index 8e7d400..f100ddc 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -80,6 +80,7 @@ public final class BluetoothLeScanner {
* @throws IllegalArgumentException If {@code callback} is null.
*/
public void startScan(final ScanCallback callback) {
+ checkAdapterState();
if (callback == null) {
throw new IllegalArgumentException("callback is null");
}
@@ -98,6 +99,7 @@ public final class BluetoothLeScanner {
*/
public void startScan(List<ScanFilter> filters, ScanSettings settings,
final ScanCallback callback) {
+ checkAdapterState();
if (settings == null || callback == null) {
throw new IllegalArgumentException("settings or callback is null");
}
@@ -148,6 +150,7 @@ public final class BluetoothLeScanner {
* @param callback
*/
public void stopScan(ScanCallback callback) {
+ checkAdapterState();
synchronized (mLeScanClients) {
BleScanCallbackWrapper wrapper = mLeScanClients.remove(callback);
if (wrapper == null) {
@@ -167,6 +170,7 @@ public final class BluetoothLeScanner {
* used to start scan.
*/
public void flushPendingScanResults(ScanCallback callback) {
+ checkAdapterState();
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null!");
}
@@ -445,6 +449,13 @@ public final class BluetoothLeScanner {
}
}
+ //TODO: move this api to a common util class.
+ private void checkAdapterState() {
+ if (mBluetoothAdapter.getState() != mBluetoothAdapter.STATE_ON) {
+ throw new IllegalStateException("BT Adapter is not turned ON");
+ }
+ }
+
private void postCallbackError(final ScanCallback callback, final int errorCode) {
mHandler.post(new Runnable() {
@Override
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 3f01dd2..900b41d 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -331,6 +331,46 @@ public class ColorStateList implements Parcelable {
return mColors;
}
+ /**
+ * If the color state list does not already have an entry matching the
+ * specified state, prepends a state set and color pair to a color state
+ * list.
+ * <p>
+ * This is a workaround used in TimePicker and DatePicker until we can
+ * add support for theme attributes in ColorStateList.
+ *
+ * @param colorStateList the source color state list
+ * @param state the state to prepend
+ * @param color the color to use for the given state
+ * @return a new color state list, or the source color state list if there
+ * was already a matching state set
+ *
+ * @hide Remove when we can support theme attributes.
+ */
+ public static ColorStateList addFirstIfMissing(
+ ColorStateList colorStateList, int state, int color) {
+ final int[][] inputStates = colorStateList.getStates();
+ for (int i = 0; i < inputStates.length; i++) {
+ final int[] inputState = inputStates[i];
+ for (int j = 0; j < inputState.length; j++) {
+ if (inputState[i] == state) {
+ return colorStateList;
+ }
+ }
+ }
+
+ final int[][] outputStates = new int[inputStates.length + 1][];
+ System.arraycopy(inputStates, 0, outputStates, 1, inputStates.length);
+ outputStates[0] = new int[] { state };
+
+ final int[] inputColors = colorStateList.getColors();
+ final int[] outputColors = new int[inputColors.length + 1];
+ System.arraycopy(inputColors, 0, outputColors, 1, inputColors.length);
+ outputColors[0] = color;
+
+ return new ColorStateList(outputStates, outputColors);
+ }
+
@Override
public String toString() {
return "ColorStateList{" +
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 645f7df..8607bbc 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -400,6 +400,8 @@ public class TypedArray {
return csl.getDefaultColor();
}
return defValue;
+ } else if (type == TypedValue.TYPE_ATTRIBUTE) {
+ throw new RuntimeException("Failed to resolve attribute at index " + index);
}
throw new UnsupportedOperationException("Can't convert to color: type=0x"
@@ -422,6 +424,9 @@ public class TypedArray {
final TypedValue value = mValue;
if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
+ if (value.type == TypedValue.TYPE_ATTRIBUTE) {
+ throw new RuntimeException("Failed to resolve attribute at index " + index);
+ }
return mResources.loadColorStateList(value, value.resourceId);
}
return null;
@@ -449,6 +454,8 @@ public class TypedArray {
} else if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
return data[index+AssetManager.STYLE_DATA];
+ } else if (type == TypedValue.TYPE_ATTRIBUTE) {
+ throw new RuntimeException("Failed to resolve attribute at index " + index);
}
throw new UnsupportedOperationException("Can't convert to integer: type=0x"
@@ -484,6 +491,8 @@ public class TypedArray {
} else if (type == TypedValue.TYPE_DIMENSION) {
return TypedValue.complexToDimension(
data[index+AssetManager.STYLE_DATA], mMetrics);
+ } else if (type == TypedValue.TYPE_ATTRIBUTE) {
+ throw new RuntimeException("Failed to resolve attribute at index " + index);
}
throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
@@ -520,6 +529,8 @@ public class TypedArray {
} else if (type == TypedValue.TYPE_DIMENSION) {
return TypedValue.complexToDimensionPixelOffset(
data[index+AssetManager.STYLE_DATA], mMetrics);
+ } else if (type == TypedValue.TYPE_ATTRIBUTE) {
+ throw new RuntimeException("Failed to resolve attribute at index " + index);
}
throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
@@ -557,6 +568,8 @@ public class TypedArray {
} else if (type == TypedValue.TYPE_DIMENSION) {
return TypedValue.complexToDimensionPixelSize(
data[index+AssetManager.STYLE_DATA], mMetrics);
+ } else if (type == TypedValue.TYPE_ATTRIBUTE) {
+ throw new RuntimeException("Failed to resolve attribute at index " + index);
}
throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
@@ -589,6 +602,8 @@ public class TypedArray {
} else if (type == TypedValue.TYPE_DIMENSION) {
return TypedValue.complexToDimensionPixelSize(
data[index+AssetManager.STYLE_DATA], mMetrics);
+ } else if (type == TypedValue.TYPE_ATTRIBUTE) {
+ throw new RuntimeException("Failed to resolve attribute at index " + index);
}
throw new RuntimeException(getPositionDescription()
@@ -655,6 +670,8 @@ public class TypedArray {
} else if (type == TypedValue.TYPE_FRACTION) {
return TypedValue.complexToFraction(
data[index+AssetManager.STYLE_DATA], base, pbase);
+ } else if (type == TypedValue.TYPE_ATTRIBUTE) {
+ throw new RuntimeException("Failed to resolve attribute at index " + index);
}
throw new UnsupportedOperationException("Can't convert to fraction: type=0x"
@@ -731,14 +748,8 @@ public class TypedArray {
final TypedValue value = mValue;
if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
- if (false) {
- System.out.println("******************************************************************");
- System.out.println("Got drawable resource: type="
- + value.type
- + " str=" + value.string
- + " int=0x" + Integer.toHexString(value.data)
- + " cookie=" + value.assetCookie);
- System.out.println("******************************************************************");
+ if (value.type == TypedValue.TYPE_ATTRIBUTE) {
+ throw new RuntimeException("Failed to resolve attribute at index " + index);
}
return mResources.loadDrawable(value, value.resourceId, mTheme);
}
@@ -762,15 +773,6 @@ public class TypedArray {
final TypedValue value = mValue;
if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
- if (false) {
- System.out.println("******************************************************************");
- System.out.println("Got drawable resource: type="
- + value.type
- + " str=" + value.string
- + " int=0x" + Integer.toHexString(value.data)
- + " cookie=" + value.assetCookie);
- System.out.println("******************************************************************");
- }
return mResources.getTextArray(value.resourceId);
}
return null;
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 6cb6a24..dd16f6f 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1934,7 +1934,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* android.sync.frameNumber to a non-negative value).</p>
* <p>This defines the maximum distance (in number of metadata results),
* between android.sync.frameNumber and the equivalent
- * android.request.frameCount.</p>
+ * frame number for that result.</p>
* <p>In other words this acts as an upper boundary for how many frames
* must occur before the camera device knows for a fact that the new
* submitted camera settings have been applied in outgoing frames.</p>
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index ebbfc63..9f7ae60 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -664,7 +664,7 @@ public abstract class CameraMetadata<TKey> {
/**
* <p>Every frame has the requests immediately applied.</p>
* <p>Furthermore for all results,
- * <code>android.sync.frameNumber == android.request.frameCount</code></p>
+ * <code>android.sync.frameNumber == CaptureResult#getFrameNumber()</code></p>
* <p>Changing controls over multiple requests one after another will
* produce results that have those controls applied atomically
* each frame.</p>
@@ -679,6 +679,7 @@ public abstract class CameraMetadata<TKey> {
* <p>By submitting a series of identical requests, the camera device
* will eventually have the camera settings applied, but it is
* unknown when that exact point will be.</p>
+ * <p>All LEGACY capability devices will have this as their maxLatency.</p>
* @see CameraCharacteristics#SYNC_MAX_LATENCY
*/
public static final int SYNC_MAX_LATENCY_UNKNOWN = -1;
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 20a04f0..4f80bc4 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -17,6 +17,7 @@
package android.hardware.camera2;
import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.impl.CaptureResultExtras;
import android.hardware.camera2.impl.PublicKey;
import android.hardware.camera2.impl.SyntheticKey;
import android.hardware.camera2.utils.TypeReference;
@@ -142,12 +143,16 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
private final CameraMetadataNative mResults;
private final CaptureRequest mRequest;
private final int mSequenceId;
+ private final long mFrameNumber;
/**
* Takes ownership of the passed-in properties object
+ *
+ * <p>For internal use only</p>
* @hide
*/
- public CaptureResult(CameraMetadataNative results, CaptureRequest parent, int sequenceId) {
+ public CaptureResult(CameraMetadataNative results, CaptureRequest parent,
+ CaptureResultExtras extras) {
if (results == null) {
throw new IllegalArgumentException("results was null");
}
@@ -156,12 +161,17 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
throw new IllegalArgumentException("parent was null");
}
+ if (extras == null) {
+ throw new IllegalArgumentException("extras was null");
+ }
+
mResults = CameraMetadataNative.move(results);
if (mResults.isEmpty()) {
throw new AssertionError("Results must not be empty");
}
mRequest = parent;
- mSequenceId = sequenceId;
+ mSequenceId = extras.getRequestId();
+ mFrameNumber = extras.getFrameNumber();
}
/**
@@ -190,6 +200,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
mRequest = null;
mSequenceId = sequenceId;
+ mFrameNumber = -1;
}
/**
@@ -288,11 +299,10 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* for every new result or failure; and the scope is the lifetime of the
* {@link CameraDevice}.</p>
*
- * @return int frame number
+ * @return The frame number
*/
- public int getFrameNumber() {
- // TODO: @hide REQUEST_FRAME_COUNT
- return get(REQUEST_FRAME_COUNT);
+ public long getFrameNumber() {
+ return mFrameNumber;
}
/**
@@ -2026,8 +2036,10 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* increases with every new result (that is, each new result has a unique
* frameCount value).</p>
* <p>Reset on release()</p>
+ * @deprecated
+ * @hide
*/
- @PublicKey
+ @Deprecated
public static final Key<Integer> REQUEST_FRAME_COUNT =
new Key<Integer>("android.request.frameCount", int.class);
diff --git a/core/java/android/hardware/camera2/TotalCaptureResult.java b/core/java/android/hardware/camera2/TotalCaptureResult.java
index 226f09d..ec4bc7d 100644
--- a/core/java/android/hardware/camera2/TotalCaptureResult.java
+++ b/core/java/android/hardware/camera2/TotalCaptureResult.java
@@ -17,6 +17,7 @@
package android.hardware.camera2;
import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.impl.CaptureResultExtras;
import java.util.Collections;
import java.util.List;
@@ -51,8 +52,9 @@ public final class TotalCaptureResult extends CaptureResult {
* Takes ownership of the passed-in properties object
* @hide
*/
- public TotalCaptureResult(CameraMetadataNative results, CaptureRequest parent, int sequenceId) {
- super(results, parent, sequenceId);
+ public TotalCaptureResult(CameraMetadataNative results, CaptureRequest parent,
+ CaptureResultExtras extras) {
+ super(results, parent, extras);
}
/**
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index ed4e457..18b1202 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -313,6 +313,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
return mCameraId;
}
+ @Override
public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
// Treat a null input the same an empty list
if (outputs == null) {
@@ -448,6 +449,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
}
}
+ @Override
public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
throws CameraAccessException {
if (DEBUG) {
@@ -458,6 +460,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
return submitCaptureRequest(requestList, listener, handler, /*streaming*/false);
}
+ @Override
public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
Handler handler) throws CameraAccessException {
if (requests == null || requests.isEmpty()) {
@@ -610,6 +613,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
}
}
+ @Override
public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Handler handler) throws CameraAccessException {
List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
@@ -617,6 +621,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
return submitCaptureRequest(requestList, listener, handler, /*streaming*/true);
}
+ @Override
public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
Handler handler) throws CameraAccessException {
if (requests == null || requests.isEmpty()) {
@@ -625,6 +630,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
return submitCaptureRequest(requests, listener, handler, /*streaming*/true);
}
+ @Override
public void stopRepeating() throws CameraAccessException {
synchronized(mInterfaceLock) {
@@ -675,6 +681,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
}
}
+ @Override
public void flush() throws CameraAccessException {
synchronized(mInterfaceLock) {
checkIfCameraClosedOrInError();
@@ -1031,8 +1038,10 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
CaptureResultExtras resultExtras) throws RemoteException {
int requestId = resultExtras.getRequestId();
+ long frameNumber = resultExtras.getFrameNumber();
+
if (DEBUG) {
- Log.v(TAG, "Received result frame " + resultExtras.getFrameNumber() + " for id "
+ Log.v(TAG, "Received result frame " + frameNumber + " for id "
+ requestId);
}
@@ -1051,7 +1060,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
// Update tracker (increment counter) when it's not a partial result.
if (!isPartialResult) {
- mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(),
+ mFrameNumberTracker.updateTracker(frameNumber,
/*error*/false);
}
@@ -1060,7 +1069,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
if (DEBUG) {
Log.d(TAG,
"holder is null, early return at frame "
- + resultExtras.getFrameNumber());
+ + frameNumber);
}
return;
}
@@ -1069,7 +1078,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
if (DEBUG) {
Log.d(TAG,
"camera is closed, early return at frame "
- + resultExtras.getFrameNumber());
+ + frameNumber);
}
return;
}
@@ -1082,7 +1091,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
// Either send a partial result or the final capture completed result
if (isPartialResult) {
final CaptureResult resultAsCapture =
- new CaptureResult(result, request, requestId);
+ new CaptureResult(result, request, resultExtras);
// Partial result
resultDispatch = new Runnable() {
@@ -1098,7 +1107,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
};
} else {
final TotalCaptureResult resultAsCapture =
- new TotalCaptureResult(result, request, requestId);
+ new TotalCaptureResult(result, request, resultExtras);
// Final capture result
resultDispatch = new Runnable() {
diff --git a/core/java/android/hardware/camera2/legacy/CaptureCollector.java b/core/java/android/hardware/camera2/legacy/CaptureCollector.java
index ab31d8c..af58a8a 100644
--- a/core/java/android/hardware/camera2/legacy/CaptureCollector.java
+++ b/core/java/android/hardware/camera2/legacy/CaptureCollector.java
@@ -15,11 +15,12 @@
*/
package android.hardware.camera2.legacy;
-import android.hardware.camera2.impl.CameraMetadataNative;
import android.util.Log;
+import android.util.MutableLong;
import android.util.Pair;
import java.util.ArrayDeque;
+import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
@@ -77,7 +78,7 @@ public class CaptureCollector {
if (needsPreview && isPreviewCompleted()) {
CaptureCollector.this.onPreviewCompleted();
}
- CaptureCollector.this.onRequestCompleted(mRequest, mLegacy, mTimestamp);
+ CaptureCollector.this.onRequestCompleted(this);
}
}
@@ -176,13 +177,13 @@ public class CaptureCollector {
private final ArrayDeque<CaptureHolder> mJpegProduceQueue;
private final ArrayDeque<CaptureHolder> mPreviewCaptureQueue;
private final ArrayDeque<CaptureHolder> mPreviewProduceQueue;
+ private final ArrayList<CaptureHolder> mCompletedRequests = new ArrayList<>();
private final ReentrantLock mLock = new ReentrantLock();
private final Condition mIsEmpty;
private final Condition mPreviewsEmpty;
private final Condition mNotFull;
private final CameraDeviceState mDeviceState;
- private final LegacyResultMapper mMapper = new LegacyResultMapper();
private int mInFlight = 0;
private int mInFlightPreviews = 0;
private final int mMaxInFlight;
@@ -320,6 +321,54 @@ public class CaptureCollector {
}
/**
+ * Wait for the specified request to be completed (all buffers available).
+ *
+ * <p>May not wait for the same request more than once, since a successful wait
+ * will erase the history of that request.</p>
+ *
+ * @param holder the {@link RequestHolder} for this request.
+ * @param timeout a timeout to use for this call.
+ * @param unit the units to use for the timeout.
+ * @param timestamp the timestamp of the request will be written out to here, in ns
+ *
+ * @return {@code false} if this method timed out.
+ *
+ * @throws InterruptedException if this thread is interrupted.
+ */
+ public boolean waitForRequestCompleted(RequestHolder holder, long timeout, TimeUnit unit,
+ MutableLong timestamp)
+ throws InterruptedException {
+ long nanos = unit.toNanos(timeout);
+ final ReentrantLock lock = this.mLock;
+ lock.lock();
+ try {
+ while (!removeRequestIfCompleted(holder, /*out*/timestamp)) {
+ if (nanos <= 0) {
+ return false;
+ }
+ nanos = mNotFull.awaitNanos(nanos);
+ }
+ return true;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private boolean removeRequestIfCompleted(RequestHolder holder, MutableLong timestamp) {
+ int i = 0;
+ for (CaptureHolder h : mCompletedRequests) {
+ if (h.mRequest.equals(holder)) {
+ timestamp.value = h.mTimestamp;
+ mCompletedRequests.remove(i);
+ return true;
+ }
+ i++;
+ }
+
+ return false;
+ }
+
+ /**
* Called to alert the {@link CaptureCollector} that the jpeg capture has begun.
*
* @param timestamp the time of the jpeg capture.
@@ -431,8 +480,9 @@ public class CaptureCollector {
}
}
- private void onRequestCompleted(RequestHolder request, LegacyRequest legacyHolder,
- long timestamp) {
+ private void onRequestCompleted(CaptureHolder capture) {
+ RequestHolder request = capture.mRequest;
+
mInFlight--;
if (DEBUG) {
Log.d(TAG, "Completed request " + request.getRequestId() +
@@ -442,12 +492,12 @@ public class CaptureCollector {
throw new IllegalStateException(
"More captures completed than requests queued.");
}
+
+ mCompletedRequests.add(capture);
+
mNotFull.signalAll();
if (mInFlight == 0) {
mIsEmpty.signalAll();
}
- CameraMetadataNative result = mMapper.cachedConvertResultMetadata(
- legacyHolder, timestamp);
- mDeviceState.setCaptureResult(request, result);
}
}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java b/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java
new file mode 100644
index 0000000..e576b43
--- /dev/null
+++ b/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java
@@ -0,0 +1,301 @@
+/*
+ * 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.legacy;
+
+import android.hardware.Camera;
+import android.hardware.Camera.Parameters;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.utils.ParamsUtils;
+import android.util.Log;
+
+import java.util.Objects;
+
+import static android.hardware.camera2.CaptureRequest.*;
+import static com.android.internal.util.Preconditions.*;
+
+/**
+ * Map capture request data into legacy focus state transitions.
+ *
+ * <p>This object will asynchronously process auto-focus changes, so no interaction
+ * with it is necessary beyond reading the current state and updating with the latest trigger.</p>
+ */
+@SuppressWarnings("deprecation")
+public class LegacyFocusStateMapper {
+ private static String TAG = "LegacyFocusStateMapper";
+ private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+
+ private final Camera mCamera;
+
+ private int mAfStatePrevious = CONTROL_AF_STATE_INACTIVE;
+ private String mAfModePrevious = null;
+
+ /** Guard mAfRun and mAfState */
+ private final Object mLock = new Object();
+ /** Guard access with mLock */
+ private int mAfRun = 0;
+ /** Guard access with mLock */
+ private int mAfState = CONTROL_AF_STATE_INACTIVE;
+
+ /**
+ * Instantiate a new focus state mapper.
+ *
+ * @param camera a non-{@code null} camera1 device
+ *
+ * @throws NullPointerException if any of the args were {@code null}
+ */
+ public LegacyFocusStateMapper(Camera camera) {
+ mCamera = checkNotNull(camera, "camera must not be null");
+ }
+
+ /**
+ * Process the AF triggers from the request as a camera1 autofocus routine.
+ *
+ * <p>This method should be called after the parameters are {@link LegacyRequestMapper mapped}
+ * with the request.</p>
+ *
+ * <p>Callbacks are processed in the background, and the next call to {@link #mapResultTriggers}
+ * will have the latest AF state as reflected by the camera1 callbacks.</p>
+ *
+ * <p>None of the arguments will be mutated.</p>
+ *
+ * @param captureRequest a non-{@code null} request
+ * @param parameters a non-{@code null} parameters corresponding to this request (read-only)
+ */
+ public void processRequestTriggers(CaptureRequest captureRequest,
+ Camera.Parameters parameters) {
+ checkNotNull(captureRequest, "captureRequest must not be null");
+
+ /*
+ * control.afTrigger
+ */
+ int afTrigger = ParamsUtils.getOrDefault(captureRequest, CONTROL_AF_TRIGGER,
+ CONTROL_AF_TRIGGER_IDLE);
+
+ final String afMode = parameters.getFocusMode();
+
+ if (!Objects.equals(mAfModePrevious, afMode)) {
+ if (VERBOSE) {
+ Log.v(TAG, "processRequestTriggers - AF mode switched from " + mAfModePrevious +
+ " to " + afMode);
+ }
+
+ // Switching modes always goes back to INACTIVE; ignore callbacks from previous modes
+
+ synchronized (mLock) {
+ ++mAfRun;
+ mAfState = CONTROL_AF_STATE_INACTIVE;
+ }
+ mCamera.cancelAutoFocus();
+ }
+
+ mAfModePrevious = afMode;
+
+ // Passive AF Scanning
+ {
+ final int currentAfRun;
+
+ synchronized (mLock) {
+ currentAfRun = mAfRun;
+ }
+
+ mCamera.setAutoFocusMoveCallback(new Camera.AutoFocusMoveCallback() {
+ @Override
+ public void onAutoFocusMoving(boolean start, Camera camera) {
+ synchronized (mLock) {
+ int latestAfRun = mAfRun;
+
+ if (VERBOSE) {
+ Log.v(TAG, "onAutoFocusMoving - start " + start + " latest AF run " +
+ latestAfRun + ", last AF run " + currentAfRun);
+ }
+
+ if (currentAfRun != latestAfRun) {
+ Log.d(TAG,
+ "onAutoFocusMoving - ignoring move callbacks from old af run"
+ + currentAfRun);
+ return;
+ }
+
+ int newAfState = start ?
+ CONTROL_AF_STATE_PASSIVE_SCAN :
+ CONTROL_AF_STATE_PASSIVE_FOCUSED;
+ // We never send CONTROL_AF_STATE_PASSIVE_UNFOCUSED
+
+ switch (afMode) {
+ case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
+ case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
+ break;
+ // This callback should never be sent in any other AF mode
+ default:
+ Log.w(TAG, "onAutoFocus - got unexpected onAutoFocus in mode "
+ + afMode);
+
+ }
+
+ mAfState = newAfState;
+ }
+ }
+ });
+ }
+
+ // AF Locking
+ switch (afTrigger) {
+ case CONTROL_AF_TRIGGER_START:
+
+ int afStateAfterStart;
+ switch (afMode) {
+ case Parameters.FOCUS_MODE_AUTO:
+ case Parameters.FOCUS_MODE_MACRO:
+ afStateAfterStart = CONTROL_AF_STATE_ACTIVE_SCAN;
+ break;
+ case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
+ case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
+ afStateAfterStart = CONTROL_AF_STATE_PASSIVE_SCAN;
+ default:
+ // EDOF, INFINITY
+ afStateAfterStart = CONTROL_AF_STATE_INACTIVE;
+ }
+
+ final int currentAfRun;
+ synchronized (mLock) {
+ currentAfRun = ++mAfRun;
+ mAfState = afStateAfterStart;
+ }
+
+ if (VERBOSE) {
+ Log.v(TAG, "processRequestTriggers - got AF_TRIGGER_START, " +
+ "new AF run is " + currentAfRun);
+ }
+
+ mCamera.autoFocus(new Camera.AutoFocusCallback() {
+ @Override
+ public void onAutoFocus(boolean success, Camera camera) {
+ synchronized (mLock) {
+ int latestAfRun = mAfRun;
+
+ if (VERBOSE) {
+ Log.v(TAG, "onAutoFocus - success " + success + " latest AF run " +
+ latestAfRun + ", last AF run " + currentAfRun);
+ }
+
+ // Ignore old auto-focus results, since another trigger was requested
+ if (latestAfRun != currentAfRun) {
+ Log.d(TAG, String.format("onAutoFocus - ignoring AF callback " +
+ "(old run %d, new run %d)", currentAfRun, latestAfRun));
+
+ return;
+ }
+
+ int newAfState = success ?
+ CONTROL_AF_STATE_FOCUSED_LOCKED :
+ CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
+
+ switch (afMode) {
+ case Parameters.FOCUS_MODE_AUTO:
+ case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
+ case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
+ case Parameters.FOCUS_MODE_MACRO:
+ break;
+ // This callback should never be sent in any other AF mode
+ default:
+ Log.w(TAG, "onAutoFocus - got unexpected onAutoFocus in mode "
+ + afMode);
+
+ }
+
+ mAfState = newAfState;
+ }
+ }
+ });
+
+ break;
+ case CONTROL_AF_TRIGGER_CANCEL:
+ synchronized (mLock) {
+ int updatedAfRun;
+
+ synchronized (mLock) {
+ updatedAfRun = ++mAfRun;
+ mAfState = CONTROL_AF_STATE_INACTIVE;
+ }
+
+ mCamera.cancelAutoFocus();
+
+ if (VERBOSE) {
+ Log.v(TAG, "processRequestTriggers - got AF_TRIGGER_CANCEL, " +
+ "new AF run is " + updatedAfRun);
+ }
+ }
+
+ break;
+ case CONTROL_AF_TRIGGER_IDLE:
+ // No action necessary. The callbacks will handle transitions.
+ break;
+ default:
+ Log.w(TAG, "mapTriggers - ignoring unknown control.afTrigger = " + afTrigger);
+ }
+ }
+
+ /**
+ * Update the {@code result} camera metadata map with the new value for the
+ * {@code control.afState}.
+ *
+ * <p>AF callbacks are processed in the background, and each call to {@link #mapResultTriggers}
+ * will have the latest AF state as reflected by the camera1 callbacks.</p>
+ *
+ * @param result a non-{@code null} result
+ */
+ public void mapResultTriggers(CameraMetadataNative result) {
+ checkNotNull(result, "result must not be null");
+
+ int newAfState;
+ synchronized (mLock) {
+ newAfState = mAfState;
+ }
+
+ if (VERBOSE && newAfState != mAfStatePrevious) {
+ Log.v(TAG, String.format("mapResultTriggers - afState changed from %s to %s",
+ afStateToString(mAfStatePrevious), afStateToString(newAfState)));
+ }
+
+ result.set(CaptureResult.CONTROL_AF_STATE, newAfState);
+
+ mAfStatePrevious = newAfState;
+ }
+
+ private static String afStateToString(int afState) {
+ switch (afState) {
+ case CONTROL_AF_STATE_ACTIVE_SCAN:
+ return "ACTIVE_SCAN";
+ case CONTROL_AF_STATE_FOCUSED_LOCKED:
+ return "FOCUSED_LOCKED";
+ case CONTROL_AF_STATE_INACTIVE:
+ return "INACTIVE";
+ case CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
+ return "NOT_FOCUSED_LOCKED";
+ case CONTROL_AF_STATE_PASSIVE_FOCUSED:
+ return "PASSIVE_FOCUSED";
+ case CONTROL_AF_STATE_PASSIVE_SCAN:
+ return "PASSIVE_SCAN";
+ case CONTROL_AF_STATE_PASSIVE_UNFOCUSED:
+ return "PASSIVE_UNFOCUSED";
+ default :
+ return "UNKNOWN(" + afState + ")";
+ }
+ }
+}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index 157c159..633bada 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -48,6 +48,7 @@ import static android.hardware.camera2.legacy.ParameterUtils.*;
* Provide legacy-specific implementations of camera2 metadata for legacy devices, such as the
* camera characteristics.
*/
+@SuppressWarnings("deprecation")
public class LegacyMetadataMapper {
private static final String TAG = "LegacyMetadataMapper";
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
@@ -87,8 +88,8 @@ public class LegacyMetadataMapper {
*/
static final boolean LIE_ABOUT_AE_STATE = false;
static final boolean LIE_ABOUT_AE_MAX_REGIONS = false;
- static final boolean LIE_ABOUT_AF = true;
- static final boolean LIE_ABOUT_AF_MAX_REGIONS = true;
+ static final boolean LIE_ABOUT_AF = false;
+ static final boolean LIE_ABOUT_AF_MAX_REGIONS = false;
static final boolean LIE_ABOUT_AWB_STATE = false;
static final boolean LIE_ABOUT_AWB = true;
@@ -162,6 +163,10 @@ public class LegacyMetadataMapper {
*/
mapControlAe(m, p);
/*
+ * control.af*
+ */
+ mapControlAf(m, p);
+ /*
* control.awb*
*/
mapControlAwb(m, p);
@@ -379,6 +384,54 @@ public class LegacyMetadataMapper {
}
}
+
+ @SuppressWarnings({"unchecked"})
+ private static void mapControlAf(CameraMetadataNative m, Camera.Parameters p) {
+ /*
+ * control.afAvailableModes
+ */
+ {
+ List<String> focusModes = p.getSupportedFocusModes();
+
+ String[] focusModeStrings = new String[] {
+ Camera.Parameters.FOCUS_MODE_AUTO,
+ Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE,
+ Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO,
+ Camera.Parameters.FOCUS_MODE_EDOF,
+ Camera.Parameters.FOCUS_MODE_INFINITY,
+ Camera.Parameters.FOCUS_MODE_MACRO,
+ Camera.Parameters.FOCUS_MODE_FIXED,
+ };
+
+ int[] focusModeInts = new int[] {
+ CONTROL_AF_MODE_AUTO,
+ CONTROL_AF_MODE_CONTINUOUS_PICTURE,
+ CONTROL_AF_MODE_CONTINUOUS_VIDEO,
+ CONTROL_AF_MODE_EDOF,
+ CONTROL_AF_MODE_OFF,
+ CONTROL_AF_MODE_MACRO,
+ CONTROL_AF_MODE_OFF
+ };
+
+ List<Integer> afAvail = ArrayUtils.convertStringListToIntList(
+ focusModes, focusModeStrings, focusModeInts);
+
+ // No AF modes supported? That's unpossible!
+ if (afAvail == null || afAvail.size() == 0) {
+ Log.w(TAG, "No AF modes supported (HAL bug); defaulting to AF_MODE_OFF only");
+ afAvail = new ArrayList<Integer>(/*capacity*/1);
+ afAvail.add(CONTROL_AF_MODE_OFF);
+ }
+
+ m.set(CONTROL_AF_AVAILABLE_MODES, ArrayUtils.toIntArray(afAvail));
+
+ if (VERBOSE) {
+ Log.v(TAG, "mapControlAf - control.afAvailableModes set to " +
+ ListUtils.listToString(afAvail));
+ }
+ }
+ }
+
private static void mapControlAwb(CameraMetadataNative m, Camera.Parameters p) {
if (!LIE_ABOUT_AWB) {
throw new AssertionError("Not implemented yet");
@@ -548,7 +601,6 @@ public class LegacyMetadataMapper {
CaptureResult.JPEG_QUALITY ,
CaptureResult.JPEG_THUMBNAIL_QUALITY ,
CaptureResult.LENS_FOCAL_LENGTH ,
- CaptureResult.REQUEST_FRAME_COUNT ,
CaptureResult.REQUEST_PIPELINE_DEPTH ,
CaptureResult.SCALER_CROP_REGION ,
CaptureResult.SENSOR_TIMESTAMP ,
@@ -794,4 +846,55 @@ public class LegacyMetadataMapper {
return tags;
}
+
+ /**
+ * Convert the requested AF mode into its equivalent supported parameter.
+ *
+ * @param mode {@code CONTROL_AF_MODE}
+ * @param supportedFocusModes list of camera1's supported focus modes
+ * @return the stringified af mode, or {@code null} if its not supported
+ */
+ static String convertAfModeToLegacy(int mode, List<String> supportedFocusModes) {
+ if (supportedFocusModes == null || supportedFocusModes.isEmpty()) {
+ Log.w(TAG, "No focus modes supported; API1 bug");
+ return null;
+ }
+
+ String param = null;
+ switch (mode) {
+ case CONTROL_AF_MODE_AUTO:
+ param = Parameters.FOCUS_MODE_AUTO;
+ break;
+ case CONTROL_AF_MODE_CONTINUOUS_PICTURE:
+ param = Parameters.FOCUS_MODE_CONTINUOUS_PICTURE;
+ break;
+ case CONTROL_AF_MODE_CONTINUOUS_VIDEO:
+ param = Parameters.FOCUS_MODE_CONTINUOUS_VIDEO;
+ break;
+ case CONTROL_AF_MODE_EDOF:
+ param = Parameters.FOCUS_MODE_EDOF;
+ break;
+ case CONTROL_AF_MODE_MACRO:
+ param = Parameters.FOCUS_MODE_MACRO;
+ break;
+ case CONTROL_AF_MODE_OFF:
+ if (supportedFocusModes.contains(Parameters.FOCUS_MODE_FIXED)) {
+ param = Parameters.FOCUS_MODE_FIXED;
+ } else {
+ param = Parameters.FOCUS_MODE_INFINITY;
+ }
+ }
+
+ if (!supportedFocusModes.contains(param)) {
+ // Weed out bad user input by setting to the first arbitrary focus mode
+ String defaultMode = supportedFocusModes.get(0);
+ Log.w(TAG,
+ String.format(
+ "convertAfModeToLegacy - ignoring unsupported mode %d, " +
+ "defaulting to %s", mode, defaultMode));
+ param = defaultMode;
+ }
+
+ return param;
+ }
}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
index 4a9afa6..fbfc39f 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
@@ -23,6 +23,7 @@ import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.MeteringRectangle;
import android.hardware.camera2.utils.ListUtils;
+import android.hardware.camera2.utils.ParamsUtils;
import android.util.Log;
import android.util.Range;
import android.util.Size;
@@ -38,6 +39,7 @@ import static android.hardware.camera2.CaptureRequest.*;
/**
* Provide legacy-specific implementations of camera2 CaptureRequest for legacy devices.
*/
+@SuppressWarnings("deprecation")
public class LegacyRequestMapper {
private static final String TAG = "LegacyRequestMapper";
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
@@ -158,7 +160,7 @@ public class LegacyRequestMapper {
{
Range<Integer> compensationRange =
characteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);
- int compensation = getOrDefault(request,
+ int compensation = ParamsUtils.getOrDefault(request,
CONTROL_AE_EXPOSURE_COMPENSATION,
/*defaultValue*/0);
@@ -192,6 +194,23 @@ public class LegacyRequestMapper {
// control.aeMode, flash.mode
mapAeAndFlashMode(request, /*out*/params);
+ // control.afMode
+ {
+ int afMode = ParamsUtils.getOrDefault(request, CONTROL_AF_MODE,
+ /*defaultValue*/CONTROL_AF_MODE_OFF);
+ String focusMode = LegacyMetadataMapper.convertAfModeToLegacy(afMode,
+ params.getSupportedFocusModes());
+
+ if (focusMode != null) {
+ params.setFocusMode(focusMode);
+ }
+
+ if (VERBOSE) {
+ Log.v(TAG, "convertRequestToMetadata - control.afMode "
+ + afMode + " mapped to " + focusMode);
+ }
+ }
+
// control.awbLock
{
Boolean awbLock = getIfSupported(request, CONTROL_AWB_LOCK, /*defaultValue*/false,
@@ -204,6 +223,21 @@ public class LegacyRequestMapper {
// TODO: Don't add control.awbLock to availableRequestKeys if it's not supported
}
+
+ // lens.focusDistance
+ {
+ boolean infinityFocusSupported =
+ ListUtils.listContains(params.getSupportedFocusModes(),
+ Parameters.FOCUS_MODE_INFINITY);
+ Float focusDistance = getIfSupported(request, LENS_FOCUS_DISTANCE,
+ /*defaultValue*/0f, infinityFocusSupported, /*allowedValue*/0f);
+
+ if (focusDistance == null || focusDistance != 0f) {
+ Log.w(TAG,
+ "convertRequestToMetadata - Ignoring android.lens.focusDistance "
+ + infinityFocusSupported + ", only 0.0f is supported");
+ }
+ }
}
private static List<Camera.Area> convertMeteringRegionsToLegacy(
@@ -253,8 +287,8 @@ public class LegacyRequestMapper {
}
private static void mapAeAndFlashMode(CaptureRequest r, /*out*/Parameters p) {
- int flashMode = getOrDefault(r, FLASH_MODE, FLASH_MODE_OFF);
- int aeMode = getOrDefault(r, CONTROL_AE_MODE, CONTROL_AE_MODE_ON);
+ int flashMode = ParamsUtils.getOrDefault(r, FLASH_MODE, FLASH_MODE_OFF);
+ int aeMode = ParamsUtils.getOrDefault(r, CONTROL_AE_MODE, CONTROL_AE_MODE_ON);
List<String> supportedFlashModes = p.getSupportedFlashModes();
@@ -355,20 +389,6 @@ public class LegacyRequestMapper {
return legacyFps;
}
- /** Return the value set by the key, or the {@code defaultValue} if no value was set. */
- private static <T> T getOrDefault(CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue) {
- checkNotNull(r, "r must not be null");
- checkNotNull(key, "key must not be null");
- checkNotNull(defaultValue, "defaultValue must not be null");
-
- T value = r.get(key);
- if (value == null) {
- return defaultValue;
- } else {
- return value;
- }
- }
-
/**
* Return {@code null} if the value is not supported, otherwise return the retrieved key's
* value from the request (or the default value if it wasn't set).
@@ -382,7 +402,7 @@ public class LegacyRequestMapper {
private static <T> T getIfSupported(
CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue, boolean isSupported,
T allowedValue) {
- T val = getOrDefault(r, key, defaultValue);
+ T val = ParamsUtils.getOrDefault(r, key, defaultValue);
if (!isSupported) {
if (!Objects.equals(val, allowedValue)) {
diff --git a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
index 88f95e1..07852b9 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
@@ -34,11 +34,13 @@ import android.util.Size;
import java.util.ArrayList;
import java.util.List;
+import static com.android.internal.util.Preconditions.*;
import static android.hardware.camera2.CaptureResult.*;
/**
* Provide legacy-specific implementations of camera2 CaptureResult for legacy devices.
*/
+@SuppressWarnings("deprecation")
public class LegacyResultMapper {
private static final String TAG = "LegacyResultMapper";
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
@@ -60,17 +62,43 @@ public class LegacyResultMapper {
*/
public CameraMetadataNative cachedConvertResultMetadata(
LegacyRequest legacyRequest, long timestamp) {
+ CameraMetadataNative result;
+ boolean cached;
+
+ /*
+ * Attempt to look up the result from the cache if the parameters haven't changed
+ */
if (mCachedRequest != null && legacyRequest.parameters.same(mCachedRequest.parameters)) {
- CameraMetadataNative newResult = new CameraMetadataNative(mCachedResult);
+ result = new CameraMetadataNative(mCachedResult);
+ cached = true;
+ } else {
+ result = convertResultMetadata(legacyRequest, timestamp);
+ cached = false;
+
+ // Always cache a *copy* of the metadata result,
+ // since api2's client side takes ownership of it after it receives a result
+ mCachedRequest = legacyRequest;
+ mCachedResult = new CameraMetadataNative(result);
+ }
+ /*
+ * Unconditionally set fields that change in every single frame
+ */
+ {
// sensor.timestamp
- newResult.set(CaptureResult.SENSOR_TIMESTAMP, timestamp);
- return newResult;
+ result.set(SENSOR_TIMESTAMP, timestamp);
}
- mCachedRequest = legacyRequest;
- mCachedResult = convertResultMetadata(mCachedRequest, timestamp);
- return mCachedResult;
+ if (VERBOSE) {
+ Log.v(TAG, "cachedConvertResultMetadata - cached? " + cached +
+ " timestamp = " + timestamp);
+
+ Log.v(TAG, "----- beginning of result dump ------");
+ result.dumpToLog();
+ Log.v(TAG, "----- end of result dump ------");
+ }
+
+ return result;
}
/**
@@ -81,7 +109,7 @@ public class LegacyResultMapper {
*
* @return a {@link CameraMetadataNative} object containing result metadata.
*/
- public static CameraMetadataNative convertResultMetadata(LegacyRequest legacyRequest,
+ private static CameraMetadataNative convertResultMetadata(LegacyRequest legacyRequest,
long timestamp) {
CameraCharacteristics characteristics = legacyRequest.characteristics;
CaptureRequest request = legacyRequest.captureRequest;
@@ -98,17 +126,15 @@ public class LegacyResultMapper {
/*
* control
*/
- // control.afState
- if (LegacyMetadataMapper.LIE_ABOUT_AF) {
- // TODO: Implement autofocus state machine
- result.set(CaptureResult.CONTROL_AF_MODE, request.get(CaptureRequest.CONTROL_AF_MODE));
- }
/*
* control.ae*
*/
mapAe(result, characteristics, request, activeArraySize, zoomData, /*out*/params);
+ // control.afMode
+ result.set(CaptureResult.CONTROL_AF_MODE, convertLegacyAfMode(params.getFocusMode()));
+
// control.awbLock
result.set(CaptureResult.CONTROL_AWB_LOCK, params.getAutoWhiteBalanceLock());
@@ -137,10 +163,24 @@ public class LegacyResultMapper {
/*
* lens
*/
+ // lens.focusDistance
+ {
+ if (Parameters.FOCUS_MODE_INFINITY.equals(params.getFocusMode())) {
+ result.set(CaptureResult.LENS_FOCUS_DISTANCE, 0.0f);
+ }
+ }
+
// lens.focalLength
result.set(CaptureResult.LENS_FOCAL_LENGTH, params.getFocalLength());
/*
+ * request
+ */
+ // request.pipelineDepth
+ result.set(REQUEST_PIPELINE_DEPTH,
+ characteristics.get(CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH));
+
+ /*
* scaler
*/
mapScaler(result, zoomData, /*out*/params);
@@ -148,8 +188,6 @@ public class LegacyResultMapper {
/*
* sensor
*/
- // sensor.timestamp
- result.set(CaptureResult.SENSOR_TIMESTAMP, timestamp);
// TODO: Remaining result metadata tags conversions.
return result;
@@ -301,6 +339,33 @@ public class LegacyResultMapper {
m.set(CONTROL_AE_MODE, aeMode);
}
+ private static int convertLegacyAfMode(String mode) {
+ if (mode == null) {
+ Log.w(TAG, "convertLegacyAfMode - no AF mode, default to OFF");
+ return CONTROL_AF_MODE_OFF;
+ }
+
+ switch (mode) {
+ case Parameters.FOCUS_MODE_AUTO:
+ return CONTROL_AF_MODE_AUTO;
+ case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
+ return CONTROL_AF_MODE_CONTINUOUS_PICTURE;
+ case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
+ return CONTROL_AF_MODE_CONTINUOUS_VIDEO;
+ case Parameters.FOCUS_MODE_EDOF:
+ return CONTROL_AF_MODE_EDOF;
+ case Parameters.FOCUS_MODE_MACRO:
+ return CONTROL_AF_MODE_MACRO;
+ case Parameters.FOCUS_MODE_FIXED:
+ return CONTROL_AF_MODE_OFF;
+ case Parameters.FOCUS_MODE_INFINITY:
+ return CONTROL_AF_MODE_OFF;
+ default:
+ Log.w(TAG, "convertLegacyAfMode - unknown mode " + mode + " , ignoring");
+ return CONTROL_AF_MODE_OFF;
+ }
+ }
+
/** Map results for scaler.* */
private static void mapScaler(CameraMetadataNative m,
ZoomData zoomData,
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index 066b416..c556c32 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -28,6 +28,7 @@ import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
+import android.util.MutableLong;
import android.util.Pair;
import android.util.Size;
import android.view.Surface;
@@ -65,6 +66,7 @@ public class RequestThreadManager {
private final CameraDeviceState mDeviceState;
private final CaptureCollector mCaptureCollector;
+ private final LegacyFocusStateMapper mFocusStateMapper;
private static final int MSG_CONFIGURE_OUTPUTS = 1;
private static final int MSG_SUBMIT_CAPTURE_REQUEST = 2;
@@ -74,6 +76,7 @@ public class RequestThreadManager {
private static final int PREVIEW_FRAME_TIMEOUT = 300; // ms
private static final int JPEG_FRAME_TIMEOUT = 3000; // ms (same as CTS for API2)
+ private static final int REQUEST_COMPLETE_TIMEOUT = 3000; // ms (same as JPEG timeout)
private static final float ASPECT_RATIO_TOLERANCE = 0.01f;
private boolean mPreviewRunning = false;
@@ -510,7 +513,7 @@ public class RequestThreadManager {
private final Handler.Callback mRequestHandlerCb = new Handler.Callback() {
private boolean mCleanup = false;
- private LegacyResultMapper mMapper = new LegacyResultMapper();
+ private final LegacyResultMapper mMapper = new LegacyResultMapper();
@Override
public boolean handleMessage(Message msg) {
@@ -586,6 +589,8 @@ public class RequestThreadManager {
CaptureRequest request = holder.getRequest();
boolean paramsChanged = false;
+
+ // Lazily process the rest of the request
if (mLastRequest == null || mLastRequest.captureRequest != request) {
// The intermediate buffer is sometimes null, but we always need
@@ -608,6 +613,10 @@ public class RequestThreadManager {
}
}
+ // Unconditionally process AF triggers, since they're non-idempotent
+ // - must be done after setting the most-up-to-date AF mode
+ mFocusStateMapper.processRequestTriggers(request, mParams);
+
try {
boolean success = mCaptureCollector.queueRequest(holder,
mLastRequest, JPEG_FRAME_TIMEOUT, TimeUnit.MILLISECONDS);
@@ -649,6 +658,27 @@ public class RequestThreadManager {
// Update parameters to the latest that we think the camera is using
mLastRequest.setParameters(mParams);
}
+
+ MutableLong timestampMutable = new MutableLong(/*value*/0L);
+ try {
+ boolean success = mCaptureCollector.waitForRequestCompleted(holder,
+ REQUEST_COMPLETE_TIMEOUT, TimeUnit.MILLISECONDS,
+ /*out*/timestampMutable);
+
+ if (!success) {
+ Log.e(TAG, "Timed out while waiting for request to complete.");
+ }
+ } catch (InterruptedException e) {
+ // TODO: report error to CameraDevice
+ Log.e(TAG, "Interrupted during request completition.", e);
+ }
+
+ CameraMetadataNative result = mMapper.cachedConvertResultMetadata(
+ mLastRequest, timestampMutable.value);
+ // Update AF state
+ mFocusStateMapper.mapResultTriggers(result);
+
+ mDeviceState.setCaptureResult(holder, result);
}
if (DEBUG) {
long totalTime = SystemClock.elapsedRealtimeNanos() - startTime;
@@ -700,6 +730,7 @@ public class RequestThreadManager {
String name = String.format("RequestThread-%d", cameraId);
TAG = name;
mDeviceState = checkNotNull(deviceState, "deviceState must not be null");
+ mFocusStateMapper = new LegacyFocusStateMapper(mCamera);
mCaptureCollector = new CaptureCollector(MAX_IN_FLIGHT_REQUESTS, mDeviceState);
mRequestThread = new RequestHandlerThread(name, mRequestHandlerCb);
}
diff --git a/core/java/android/hardware/camera2/utils/ArrayUtils.java b/core/java/android/hardware/camera2/utils/ArrayUtils.java
index c5a56cd..24c85d0 100644
--- a/core/java/android/hardware/camera2/utils/ArrayUtils.java
+++ b/core/java/android/hardware/camera2/utils/ArrayUtils.java
@@ -67,6 +67,36 @@ public class ArrayUtils {
return null;
}
+ List<Integer> convertedList = convertStringListToIntList(list, convertFrom, convertTo);
+
+ int[] returnArray = new int[convertedList.size()];
+ for (int i = 0; i < returnArray.length; ++i) {
+ returnArray[i] = convertedList.get(i);
+ }
+
+ return returnArray;
+ }
+
+ /**
+ * Create an {@code List<Integer>} from the {@code List<>} by using {@code convertFrom} and
+ * {@code convertTo} as a one-to-one map (via the index).
+ *
+ * <p>Strings not appearing in {@code convertFrom} are ignored (with a logged warning);
+ * strings appearing in {@code convertFrom} but not {@code convertTo} are silently
+ * dropped.</p>
+ *
+ * @param list Source list of strings
+ * @param convertFrom Conversion list of strings
+ * @param convertTo Conversion list of ints
+ * @return A list of ints where the values correspond to the ones in {@code convertTo}
+ * or {@code null} if {@code list} was {@code null}
+ */
+ public static List<Integer> convertStringListToIntList(
+ List<String> list, String[] convertFrom, int[] convertTo) {
+ if (list == null) {
+ return null;
+ }
+
List<Integer> convertedList = new ArrayList<>(list.size());
for (String str : list) {
@@ -84,12 +114,33 @@ public class ArrayUtils {
}
}
- int[] returnArray = new int[convertedList.size()];
- for (int i = 0; i < returnArray.length; ++i) {
- returnArray[i] = convertedList.get(i);
+ return convertedList;
+ }
+
+ /**
+ * Convert the list of integers in {@code list} to an {@code int} array.
+ *
+ * <p>Every element in {@code list} must be non-{@code null}.</p>
+ *
+ * @param list a list of non-{@code null} integers
+ *
+ * @return a new int array containing all the elements from {@code list}
+ *
+ * @throws NullPointerException if any of the elements in {@code list} were {@code null}
+ */
+ public static int[] toIntArray(List<Integer> list) {
+ if (list == null) {
+ return null;
}
- return returnArray;
+ int[] arr = new int[list.size()];
+ int i = 0;
+ for (int elem : list) {
+ arr[i] = elem;
+ i++;
+ }
+
+ return arr;
}
private ArrayUtils() {
diff --git a/core/java/android/hardware/camera2/utils/ParamsUtils.java b/core/java/android/hardware/camera2/utils/ParamsUtils.java
index 232a4f6..976fa2e 100644
--- a/core/java/android/hardware/camera2/utils/ParamsUtils.java
+++ b/core/java/android/hardware/camera2/utils/ParamsUtils.java
@@ -19,6 +19,7 @@ package android.hardware.camera2.utils;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.hardware.camera2.CaptureRequest;
import android.util.Rational;
import android.util.Size;
@@ -175,6 +176,24 @@ public class ParamsUtils {
destination.top = source.top;
}
+ /**
+ * Return the value set by the key, or the {@code defaultValue} if no value was set.
+ *
+ * @throws NullPointerException if any of the args were {@code null}
+ */
+ public static <T> T getOrDefault(CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue) {
+ checkNotNull(r, "r must not be null");
+ checkNotNull(key, "key must not be null");
+ checkNotNull(defaultValue, "defaultValue must not be null");
+
+ T value = r.get(key);
+ if (value == null) {
+ return defaultValue;
+ } else {
+ return value;
+ }
+ }
+
private ParamsUtils() {
throw new AssertionError();
}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 5397d49..d4e6df5 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -198,10 +198,14 @@ public final class DisplayManager {
* VIRTUAL_DISPLAY_FLAG_PRIVATE. Other flags are not allowed (especially
* not VIRTUAL_DISPLAY_FLAG_PUBLIC or PRESENTATION).
*
+ * <p>
* Requires screen share permission for use.
+ * </p>
*
+ * <p>
* While a display of this type exists, the system will show some sort of
* notification to the user indicating that the screen is being shared.
+ * </p>
*
* @see #createVirtualDisplay
*/
diff --git a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
index d663714..27829a7 100644
--- a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
+++ b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
@@ -24,6 +24,8 @@ import android.os.Parcelable;
* A class to encapsulate device information for HDMI-CEC. This container
* include basic information such as logical address, physical address and
* device type, and additional information like vendor id and osd name.
+ * Also used to keep the information of non-CEC devices for which only
+ * port ID, physical address are meaningful.
*
* @hide
*/
@@ -71,6 +73,7 @@ public final class HdmiCecDeviceInfo implements Parcelable {
private final int mDeviceType;
private final int mVendorId;
private final String mDisplayName;
+ private final boolean mIsCecDevice;
/**
* A helper class to deserialize {@link HdmiCecDeviceInfo} for a parcel.
@@ -96,7 +99,7 @@ public final class HdmiCecDeviceInfo implements Parcelable {
};
/**
- * Constructor.
+ * Constructor. Used to initialize the instance for CEC device.
*
* @param logicalAddress logical address of HDMI-CEC device
* @param physicalAddress physical address of HDMI-CEC device
@@ -114,6 +117,24 @@ public final class HdmiCecDeviceInfo implements Parcelable {
mDeviceType = deviceType;
mDisplayName = displayName;
mVendorId = vendorId;
+ mIsCecDevice = true;
+ }
+
+ /**
+ * Constructor. Used to initialize the instance for non-CEC device.
+ *
+ * @param physicalAddress physical address of HDMI device
+ * @param portId HDMI port ID (1 for HDMI1)
+ * @hide
+ */
+ public HdmiCecDeviceInfo(int physicalAddress, int portId) {
+ mLogicalAddress = -1;
+ mPhysicalAddress = physicalAddress;
+ mPortId = portId;
+ mDeviceType = DEVICE_RESERVED;
+ mDisplayName = null;
+ mVendorId = 0;
+ mIsCecDevice = false;
}
/**
@@ -155,6 +176,14 @@ public final class HdmiCecDeviceInfo implements Parcelable {
}
/**
+ * Return {@code true} if the device represents an HDMI-CEC device. {@code false}
+ * if the device is either MHL or non-CEC device.
+ */
+ public boolean isCecDevice() {
+ return mIsCecDevice;
+ }
+
+ /**
* Return display (OSD) name of the device.
*/
public String getDisplayName() {
@@ -199,12 +228,19 @@ public final class HdmiCecDeviceInfo implements Parcelable {
@Override
public String toString() {
StringBuffer s = new StringBuffer();
- s.append("logical_address: ").append(mLogicalAddress).append(", ");
- s.append("physical_address: ").append(mPhysicalAddress).append(", ");
- s.append("port_id: ").append(mPortId).append(", ");
- s.append("device_type: ").append(mDeviceType).append(", ");
- s.append("vendor_id: ").append(mVendorId).append(", ");
- s.append("display_name: ").append(mDisplayName);
+ if (isCecDevice()) {
+ s.append("CEC: ");
+ s.append("logical_address: ").append(mLogicalAddress).append(", ");
+ s.append("physical_address: ").append(mPhysicalAddress).append(", ");
+ s.append("port_id: ").append(mPortId).append(", ");
+ s.append("device_type: ").append(mDeviceType).append(", ");
+ s.append("vendor_id: ").append(mVendorId).append(", ");
+ s.append("display_name: ").append(mDisplayName);
+ } else {
+ s.append("Non-CEC: ");
+ s.append("physical_address: ").append(mPhysicalAddress).append(", ");
+ s.append("port_id: ").append(mPortId).append(", ");
+ }
return s.toString();
}
diff --git a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
index 0bf4f25..b1a02c1 100644
--- a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
+++ b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
@@ -26,10 +26,8 @@ oneway interface IRecognitionStatusCallback {
* Called when the keyphrase is spoken.
*
* @param data Optional trigger audio data, if it was requested and is available.
- * TODO: See if the data being passed in works well, if not use shared memory.
- * This *MUST* not exceed 100K.
*/
- void onDetected(in SoundTrigger.RecognitionEvent recognitionEvent);
+ void onDetected(in SoundTrigger.KeyphraseRecognitionEvent recognitionEvent);
/**
* Called when the detection for the associated keyphrase stops.
*/
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
index 9adc6bc..e16ea71 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
@@ -18,8 +18,8 @@ package android.hardware.soundtrigger;
parcelable SoundTrigger.ConfidenceLevel;
parcelable SoundTrigger.Keyphrase;
+parcelable SoundTrigger.KeyphraseRecognitionEvent;
parcelable SoundTrigger.KeyphraseRecognitionExtra;
parcelable SoundTrigger.KeyphraseSoundModel;
parcelable SoundTrigger.ModuleProperties;
parcelable SoundTrigger.RecognitionConfig;
-parcelable SoundTrigger.RecognitionEvent; \ No newline at end of file
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index 3e84368..4498789 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -361,13 +361,13 @@ public class SoundTrigger {
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(uuid.toString());
dest.writeBlob(data);
- dest.writeTypedArray(keyphrases, 0);
+ dest.writeTypedArray(keyphrases, flags);
}
@Override
public String toString() {
return "KeyphraseSoundModel [keyphrases=" + Arrays.toString(keyphrases) + ", uuid="
- + uuid + ", type=" + type + ", data? " + (data != null) + "]";
+ + uuid + ", type=" + type + ", data=" + (data == null ? 0 : data.length) + "]";
}
}
@@ -504,6 +504,15 @@ public class SoundTrigger {
return false;
return true;
}
+
+ @Override
+ public String toString() {
+ return "RecognitionEvent [status=" + status + ", soundModelHandle=" + soundModelHandle
+ + ", captureAvailable=" + captureAvailable + ", captureSession="
+ + captureSession + ", captureDelayMs=" + captureDelayMs
+ + ", capturePreambleMs=" + capturePreambleMs
+ + ", data=" + (data == null ? 0 : data.length) + "]";
+ }
}
/**
@@ -551,7 +560,7 @@ public class SoundTrigger {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeByte((byte) (captureRequested ? 1 : 0));
- dest.writeTypedArray(keyphrases, 0);
+ dest.writeTypedArray(keyphrases, flags);
dest.writeBlob(data);
}
@@ -563,7 +572,8 @@ public class SoundTrigger {
@Override
public String toString() {
return "RecognitionConfig [captureRequested=" + captureRequested + ", keyphrases="
- + Arrays.toString(keyphrases) + ", data? " + (data != null) + "]";
+ + Arrays.toString(keyphrases)
+ + ", data=" + (data == null ? 0 : data.length) + "]";
}
}
@@ -611,6 +621,37 @@ public class SoundTrigger {
public int describeContents() {
return 0;
}
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + confidenceLevel;
+ result = prime * result + userId;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ConfidenceLevel other = (ConfidenceLevel) obj;
+ if (confidenceLevel != other.confidenceLevel)
+ return false;
+ if (userId != other.userId)
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "ConfidenceLevel [userId=" + userId
+ + ", confidenceLevel=" + confidenceLevel + "]";
+ }
}
/**
@@ -657,13 +698,47 @@ public class SoundTrigger {
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeInt(recognitionModes);
- dest.writeTypedArray(confidenceLevels, 0);
+ dest.writeTypedArray(confidenceLevels, flags);
}
@Override
public int describeContents() {
return 0;
}
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Arrays.hashCode(confidenceLevels);
+ result = prime * result + id;
+ result = prime * result + recognitionModes;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ KeyphraseRecognitionExtra other = (KeyphraseRecognitionExtra) obj;
+ if (!Arrays.equals(confidenceLevels, other.confidenceLevels))
+ return false;
+ if (id != other.id)
+ return false;
+ if (recognitionModes != other.recognitionModes)
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "KeyphraseRecognitionExtra [id=" + id + ", recognitionModes=" + recognitionModes
+ + ", confidenceLevels=" + Arrays.toString(confidenceLevels) + "]";
+ }
}
/**
@@ -676,7 +751,7 @@ public class SoundTrigger {
/** Additional data available for each recognized key phrases in the model */
public final boolean keyphraseInCapture;
- KeyphraseRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable,
+ public KeyphraseRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable,
int captureSession, int captureDelayMs, int capturePreambleMs, byte[] data,
boolean keyphraseInCapture, KeyphraseRecognitionExtra[] keyphraseExtras) {
super(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs,
@@ -684,6 +759,86 @@ public class SoundTrigger {
this.keyphraseInCapture = keyphraseInCapture;
this.keyphraseExtras = keyphraseExtras;
}
+
+ public static final Parcelable.Creator<KeyphraseRecognitionEvent> CREATOR
+ = new Parcelable.Creator<KeyphraseRecognitionEvent>() {
+ public KeyphraseRecognitionEvent createFromParcel(Parcel in) {
+ return KeyphraseRecognitionEvent.fromParcel(in);
+ }
+
+ public KeyphraseRecognitionEvent[] newArray(int size) {
+ return new KeyphraseRecognitionEvent[size];
+ }
+ };
+
+ private static KeyphraseRecognitionEvent fromParcel(Parcel in) {
+ int status = in.readInt();
+ int soundModelHandle = in.readInt();
+ boolean captureAvailable = in.readByte() == 1;
+ int captureSession = in.readInt();
+ int captureDelayMs = in.readInt();
+ int capturePreambleMs = in.readInt();
+ byte[] data = in.readBlob();
+ boolean keyphraseInCapture = in.readByte() == 1;
+ KeyphraseRecognitionExtra[] keyphraseExtras =
+ in.createTypedArray(KeyphraseRecognitionExtra.CREATOR);
+ return new KeyphraseRecognitionEvent(status, soundModelHandle, captureAvailable,
+ captureSession, captureDelayMs, capturePreambleMs, data, keyphraseInCapture,
+ keyphraseExtras);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(status);
+ dest.writeInt(soundModelHandle);
+ dest.writeByte((byte) (captureAvailable ? 1 : 0));
+ dest.writeInt(captureSession);
+ dest.writeInt(captureDelayMs);
+ dest.writeInt(capturePreambleMs);
+ dest.writeBlob(data);
+ dest.writeByte((byte) (keyphraseInCapture ? 1 : 0));
+ dest.writeTypedArray(keyphraseExtras, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + Arrays.hashCode(keyphraseExtras);
+ result = prime * result + (keyphraseInCapture ? 1231 : 1237);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ KeyphraseRecognitionEvent other = (KeyphraseRecognitionEvent) obj;
+ if (!Arrays.equals(keyphraseExtras, other.keyphraseExtras))
+ return false;
+ if (keyphraseInCapture != other.keyphraseInCapture)
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "KeyphraseRecognitionEvent [keyphraseExtras=" + Arrays.toString(keyphraseExtras)
+ + ", keyphraseInCapture=" + keyphraseInCapture + ", status=" + status
+ + ", soundModelHandle=" + soundModelHandle + ", captureAvailable="
+ + captureAvailable + ", captureSession=" + captureSession + ", captureDelayMs="
+ + captureDelayMs + ", capturePreambleMs=" + capturePreambleMs
+ + ", data=" + (data == null ? 0 : data.length) + "]";
+ }
}
/**
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index a8c08d55..e40ece3 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -23,6 +23,7 @@ import android.hardware.soundtrigger.KeyphraseMetadata;
import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.ConfidenceLevel;
import android.hardware.soundtrigger.SoundTrigger.Keyphrase;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
@@ -133,11 +134,6 @@ public class AlwaysOnHotwordDetector {
private final Object mLock = new Object();
private final Handler mHandler;
- /**
- * Indicates if there is a sound model enrolled for the keyphrase,
- * derived from the model management service (IVoiceInteractionManagerService).
- */
- private boolean mIsEnrolledForDetection;
private int mAvailability = STATE_NOT_READY;
/**
@@ -381,10 +377,10 @@ public class AlwaysOnHotwordDetector {
}
@Override
- public void onDetected(RecognitionEvent recognitionEvent) {
+ public void onDetected(KeyphraseRecognitionEvent event) {
Slog.i(TAG, "onDetected");
Message message = Message.obtain(mHandler, MSG_HOTWORD_DETECTED);
- message.obj = recognitionEvent.data;
+ message.obj = event.data;
message.sendToTarget();
}
@@ -436,7 +432,6 @@ public class AlwaysOnHotwordDetector {
Slog.d(TAG, "Hotword availability changed from " + mAvailability
+ " -> " + availability);
}
- mIsEnrolledForDetection = enrolled;
mAvailability = availability;
notifyStateChangedLocked();
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 81b5c20..16a161b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2904,7 +2904,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false),
@ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY_OPAQUE, name = "DIRTY_OPAQUE"),
@ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY")
- })
+ }, formatToHexString = true)
int mPrivateFlags;
int mPrivateFlags2;
int mPrivateFlags3;
@@ -2923,7 +2923,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@ViewDebug.FlagToString(mask = PUBLIC_STATUS_BAR_VISIBILITY_MASK,
equals = SYSTEM_UI_FLAG_VISIBLE,
name = "SYSTEM_UI_FLAG_VISIBLE", outputIf = true)
- })
+ }, formatToHexString = true)
int mSystemUiVisibility;
/**
@@ -2949,7 +2949,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* The view flags hold various views states.
* {@hide}
*/
- @ViewDebug.ExportedProperty
+ @ViewDebug.ExportedProperty(formatToHexString = true)
int mViewFlags;
static class TransformationInfo {
@@ -16458,6 +16458,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * @hide
+ */
+ @ViewDebug.ExportedProperty(category = "layout", indexMapping = {
+ @ViewDebug.IntToString(from = 0, to = "x"),
+ @ViewDebug.IntToString(from = 1, to = "y")
+ })
+ public int[] getLocationOnScreen() {
+ int[] location = new int[2];
+ getLocationOnScreen(location);
+ return location;
+ }
+
+ /**
* <p>Computes the coordinates of this view on the screen. The argument
* must be an array of two integers. After the method returns, the array
* contains the x and y location in that order.</p>
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 92e5e96..0b15ba7 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -180,6 +180,13 @@ public class ViewDebug {
* @return the category as String
*/
String category() default "";
+
+ /**
+ * Indicates whether or not to format an {@code int} or {@code byte} value as a hex string.
+ *
+ * @return true if the supported values should be formatted as a hex string.
+ */
+ boolean formatToHexString() default false;
}
/**
@@ -507,76 +514,76 @@ public class ViewDebug {
long durationMeasure =
(root || (view.mPrivateFlags & View.PFLAG_MEASURED_DIMENSION_SET) != 0)
- ? profileViewOperation(view, new ViewOperation<Void>() {
- public Void[] pre() {
- forceLayout(view);
- return null;
- }
+ ? profileViewOperation(view, new ViewOperation<Void>() {
+ public Void[] pre() {
+ forceLayout(view);
+ return null;
+ }
- private void forceLayout(View view) {
- view.forceLayout();
- if (view instanceof ViewGroup) {
- ViewGroup group = (ViewGroup) view;
- final int count = group.getChildCount();
- for (int i = 0; i < count; i++) {
- forceLayout(group.getChildAt(i));
- }
- }
+ private void forceLayout(View view) {
+ view.forceLayout();
+ if (view instanceof ViewGroup) {
+ ViewGroup group = (ViewGroup) view;
+ final int count = group.getChildCount();
+ for (int i = 0; i < count; i++) {
+ forceLayout(group.getChildAt(i));
}
+ }
+ }
- public void run(Void... data) {
- view.measure(view.mOldWidthMeasureSpec, view.mOldHeightMeasureSpec);
- }
+ public void run(Void... data) {
+ view.measure(view.mOldWidthMeasureSpec, view.mOldHeightMeasureSpec);
+ }
- public void post(Void... data) {
- }
- })
+ public void post(Void... data) {
+ }
+ })
: 0;
long durationLayout =
(root || (view.mPrivateFlags & View.PFLAG_LAYOUT_REQUIRED) != 0)
- ? profileViewOperation(view, new ViewOperation<Void>() {
- public Void[] pre() {
- return null;
- }
+ ? profileViewOperation(view, new ViewOperation<Void>() {
+ public Void[] pre() {
+ return null;
+ }
- public void run(Void... data) {
- view.layout(view.mLeft, view.mTop, view.mRight, view.mBottom);
- }
+ public void run(Void... data) {
+ view.layout(view.mLeft, view.mTop, view.mRight, view.mBottom);
+ }
- public void post(Void... data) {
- }
- }) : 0;
+ public void post(Void... data) {
+ }
+ }) : 0;
long durationDraw =
(root || !view.willNotDraw() || (view.mPrivateFlags & View.PFLAG_DRAWN) != 0)
- ? profileViewOperation(view, new ViewOperation<Object>() {
- public Object[] pre() {
- final DisplayMetrics metrics =
- (view != null && view.getResources() != null) ?
- view.getResources().getDisplayMetrics() : null;
- final Bitmap bitmap = metrics != null ?
- Bitmap.createBitmap(metrics, metrics.widthPixels,
- metrics.heightPixels, Bitmap.Config.RGB_565) : null;
- final Canvas canvas = bitmap != null ? new Canvas(bitmap) : null;
- return new Object[] {
- bitmap, canvas
- };
- }
+ ? profileViewOperation(view, new ViewOperation<Object>() {
+ public Object[] pre() {
+ final DisplayMetrics metrics =
+ (view != null && view.getResources() != null) ?
+ view.getResources().getDisplayMetrics() : null;
+ final Bitmap bitmap = metrics != null ?
+ Bitmap.createBitmap(metrics, metrics.widthPixels,
+ metrics.heightPixels, Bitmap.Config.RGB_565) : null;
+ final Canvas canvas = bitmap != null ? new Canvas(bitmap) : null;
+ return new Object[] {
+ bitmap, canvas
+ };
+ }
- public void run(Object... data) {
- if (data[1] != null) {
- view.draw((Canvas) data[1]);
- }
- }
+ public void run(Object... data) {
+ if (data[1] != null) {
+ view.draw((Canvas) data[1]);
+ }
+ }
- public void post(Object... data) {
- if (data[1] != null) {
- ((Canvas) data[1]).setBitmap(null);
- }
- if (data[0] != null) {
- ((Bitmap) data[0]).recycle();
- }
- }
- }) : 0;
+ public void post(Object... data) {
+ if (data[1] != null) {
+ ((Canvas) data[1]).setBitmap(null);
+ }
+ if (data[0] != null) {
+ ((Bitmap) data[0]).recycle();
+ }
+ }
+ }) : 0;
out.write(String.valueOf(durationMeasure));
out.write(' ');
out.write(String.valueOf(durationLayout));
@@ -643,12 +650,12 @@ public class ViewDebug {
} catch (RemoteException e) {
// Ignore
}
-
+
clientStream.writeInt(outRect.width());
clientStream.writeInt(outRect.height());
-
+
captureViewLayer(root, clientStream, true);
-
+
clientStream.write(2);
} finally {
clientStream.close();
@@ -666,19 +673,19 @@ public class ViewDebug {
if (id != View.NO_ID) {
name = resolveId(view.getContext(), id).toString();
}
-
+
clientStream.write(1);
clientStream.writeUTF(name);
clientStream.writeByte(localVisible ? 1 : 0);
-
+
int[] position = new int[2];
// XXX: Should happen on the UI thread
view.getLocationInWindow(position);
-
+
clientStream.writeInt(position[0]);
clientStream.writeInt(position[1]);
clientStream.flush();
-
+
Bitmap b = performViewCapture(view, true);
if (b != null) {
ByteArrayOutputStream arrayOut = new ByteArrayOutputStream(b.getWidth() *
@@ -774,7 +781,7 @@ public class ViewDebug {
Thread.currentThread().interrupt();
}
}
-
+
return null;
}
@@ -1008,10 +1015,10 @@ public class ViewDebug {
final View view = (View) object;
Callable<Object> callable = new Callable<Object>() {
- @Override
- public Object call() throws IllegalAccessException, InvocationTargetException {
- return method.invoke(view, (Object[]) null);
- }
+ @Override
+ public Object call() throws IllegalAccessException, InvocationTargetException {
+ return method.invoke(view, (Object[]) null);
+ }
};
FutureTask<Object> future = new FutureTask<Object>(callable);
// Try to use the handler provided by the view
@@ -1041,6 +1048,10 @@ public class ViewDebug {
}
}
+ private static String formatIntToHexString(int value) {
+ return "0x" + Integer.toHexString(value).toUpperCase();
+ }
+
private static void exportMethods(Context context, Object view, BufferedWriter out,
Class<?> klass, String prefix) throws IOException {
@@ -1058,7 +1069,6 @@ public class ViewDebug {
property.category().length() != 0 ? property.category() + ":" : "";
if (returnType == int.class) {
-
if (property.resolveId() && context != null) {
final int id = (Integer) methodValue;
methodValue = resolveId(context, id);
@@ -1160,6 +1170,15 @@ public class ViewDebug {
fieldValue = intValue;
}
}
+
+ if (property.formatToHexString()) {
+ fieldValue = field.get(view);
+ if (type == int.class) {
+ fieldValue = formatIntToHexString((Integer) fieldValue);
+ } else if (type == byte.class) {
+ fieldValue = "0x" + Byte.toHexString((Byte) fieldValue, true);
+ }
+ }
}
} else if (type == int[].class) {
final int[] array = (int[]) field.get(view);
@@ -1210,7 +1229,7 @@ public class ViewDebug {
final boolean test = maskResult == flagMapping.equals();
if ((test && ifTrue) || (!test && !ifTrue)) {
final String name = flagMapping.name();
- final String value = "0x" + Integer.toHexString(maskResult);
+ final String value = formatIntToHexString(maskResult);
writeEntry(out, prefix, name, "", value);
}
}
@@ -1276,7 +1295,7 @@ public class ViewDebug {
fieldValue = resources.getResourceTypeName(id) + '/' +
resources.getResourceEntryName(id);
} catch (Resources.NotFoundException e) {
- fieldValue = "id/0x" + Integer.toHexString(id);
+ fieldValue = "id/" + formatIntToHexString(id);
}
} else {
fieldValue = "NO_ID";
@@ -1393,13 +1412,13 @@ public class ViewDebug {
}
sb.append("; ");
}
- } catch (IllegalAccessException e) {
- //Exception IllegalAccess, it is OK here
- //we simply ignore this method
- } catch (InvocationTargetException e) {
- //Exception InvocationTarget, it is OK here
- //we simply ignore this method
- }
+ } catch (IllegalAccessException e) {
+ //Exception IllegalAccess, it is OK here
+ //we simply ignore this method
+ } catch (InvocationTargetException e) {
+ //Exception InvocationTarget, it is OK here
+ //we simply ignore this method
+ }
}
return sb.toString();
}
@@ -1503,7 +1522,7 @@ public class ViewDebug {
final Field f = p.getClass().getField(param);
if (f.getType() != int.class) {
throw new RuntimeException("Only integer layout parameters can be set. Field "
- + param + " is of type " + f.getType().getSimpleName());
+ + param + " is of type " + f.getType().getSimpleName());
}
f.set(p, Integer.valueOf(value));
@@ -1515,4 +1534,4 @@ public class ViewDebug {
}
});
}
-}
+} \ No newline at end of file
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 27f493a..c09440b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -203,7 +203,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
name = "CLIP_TO_PADDING"),
@ViewDebug.FlagToString(mask = FLAG_PADDING_NOT_NULL, equals = FLAG_PADDING_NOT_NULL,
name = "PADDING_NOT_NULL")
- })
+ }, formatToHexString = true)
protected int mGroupFlags;
/**
@@ -6430,7 +6430,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
equals = RTL_COMPATIBILITY_MODE_MASK, name = "RTL_COMPATIBILITY_MODE_MASK"),
@ViewDebug.FlagToString(mask = NEED_RESOLUTION_MASK,
equals = NEED_RESOLUTION_MASK, name = "NEED_RESOLUTION_MASK")
- })
+ }, formatToHexString = true)
byte mMarginFlags;
private static final int LAYOUT_DIRECTION_MASK = 0x00000003;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 597d2dd..46b9e03 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1020,7 +1020,7 @@ public interface WindowManager extends ViewManager {
name = "FLAG_TRANSLUCENT_NAVIGATION"),
@ViewDebug.FlagToString(mask = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, equals = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
name = "FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS")
- })
+ }, formatToHexString = true)
public int flags;
/**
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 8f49fb8..74c66c8 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -17,9 +17,7 @@
package android.widget;
import android.annotation.Widget;
-import android.app.UiModeManager;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.os.Parcel;
@@ -51,8 +49,6 @@ import java.util.TimeZone;
import libcore.icu.ICU;
-import static android.os.Build.VERSION_CODES.L;
-
/**
* This class is a widget for selecting a date. The date can be selected by a
* year, month, and day spinners or a {@link CalendarView}. The set of spinners
@@ -74,26 +70,21 @@ import static android.os.Build.VERSION_CODES.L;
* @attr ref android.R.styleable#DatePicker_minDate
* @attr ref android.R.styleable#DatePicker_spinnersShown
* @attr ref android.R.styleable#DatePicker_calendarViewShown
- * @attr ref android.R.styleable#DatePicker_dateSelectorDayOfWeekBackgroundColor
- * @attr ref android.R.styleable#DatePicker_dateSelectorDayOfWeekTextAppearance
- * @attr ref android.R.styleable#DatePicker_dateSelectorBackgroundColor
- * @attr ref android.R.styleable#DatePicker_dateSelectorMonthTextAppearance
- * @attr ref android.R.styleable#DatePicker_dateSelectorDayOfMonthTextAppearance
- * @attr ref android.R.styleable#DatePicker_dateSelectorYearTextAppearance
- * @attr ref android.R.styleable#DatePicker_dateSelectorYearListItemTextAppearance
- * @attr ref android.R.styleable#DatePicker_dateSelectorYearListSelectedCircleColor
+ * @attr ref android.R.styleable#DatePicker_dayOfWeekBackgroundColor
+ * @attr ref android.R.styleable#DatePicker_dayOfWeekTextAppearance
+ * @attr ref android.R.styleable#DatePicker_headerBackgroundColor
+ * @attr ref android.R.styleable#DatePicker_headerMonthTextAppearance
+ * @attr ref android.R.styleable#DatePicker_headerDayOfMonthTextAppearance
+ * @attr ref android.R.styleable#DatePicker_headerYearTextAppearance
+ * @attr ref android.R.styleable#DatePicker_yearListItemTextAppearance
+ * @attr ref android.R.styleable#DatePicker_yearListSelectorColor
* @attr ref android.R.styleable#DatePicker_calendarTextColor
*/
@Widget
public class DatePicker extends FrameLayout {
-
private static final String LOG_TAG = DatePicker.class.getSimpleName();
- private DatePickerDelegate mDelegate;
-
- private int mDefStyleAttr;
- private int mDefStyleRes;
- private Context mContext;
+ private final DatePickerDelegate mDelegate;
/**
* The callback used to indicate the user changes\d the date.
@@ -127,30 +118,16 @@ public class DatePicker extends FrameLayout {
public DatePicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- mContext = context;
- mDefStyleAttr = defStyleAttr;
- mDefStyleRes = defStyleRes;
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
- mDefStyleAttr, mDefStyleRes);
-
- // Create the correct UI delegate. Default is the legacy one.
- final boolean isLegacyMode = a.getBoolean(R.styleable.DatePicker_legacyMode,
- isLegacyMode());
-
+ final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
+ defStyleAttr, defStyleRes);
+ final boolean legacyMode = a.getBoolean(R.styleable.DatePicker_legacyMode, true);
a.recycle();
- setLegacyMode(isLegacyMode, attrs);
- }
-
- private boolean isLegacyMode() {
- UiModeManager uiModeManager =
- (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
- if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
- return true;
+ if (legacyMode) {
+ mDelegate = createLegacyUIDelegate(context, attrs, defStyleAttr, defStyleRes);
+ } else {
+ mDelegate = createNewUIDelegate(context, attrs, defStyleAttr, defStyleRes);
}
- final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
- return targetSdkVersion < L;
}
private DatePickerDelegate createLegacyUIDelegate(Context context, AttributeSet attrs,
@@ -167,16 +144,6 @@ public class DatePicker extends FrameLayout {
/**
* @hide
*/
- public void setLegacyMode(boolean isLegacyMode, AttributeSet attrs) {
- removeAllViewsInLayout();
- mDelegate = isLegacyMode ?
- createLegacyUIDelegate(mContext, attrs, mDefStyleAttr, mDefStyleRes) :
- createNewUIDelegate(mContext, attrs, mDefStyleAttr, mDefStyleRes);
- }
-
- /**
- * @hide
- */
public void setShowDoneButton(boolean showDoneButton) {
mDelegate.setShowDoneButton(showDoneButton);
}
@@ -375,182 +342,6 @@ public class DatePicker extends FrameLayout {
mDelegate.setSpinnersShown(shown);
}
- /**
- * Sets the background color for the date selector's day of week.
- *
- * @param color The background color.
- *
- * @attr ref android.R.styleable#DatePicker_dateSelectorDayOfWeekBackgroundColor
- */
- public void setDateSelectorDayOfWeekBackgroundColor(int color) {
- mDelegate.setDateSelectorDayOfWeekBackgroundColor(color);
- }
-
- /**
- * Gets the background color for the date selector's day of week.
- *
- * @return The text appearance resource id.
- *
- * @attr ref android.R.styleable#DatePicker_dateSelectorDayOfWeekBackgroundColor
- */
- public int getDateSelectorDayOfWeekBackgroundColor() {
- return mDelegate.getDateSelectorDayOfWeekBackgroundColor();
- }
-
- /**
- * Sets the text appearance for the date selector's day of week.
- *
- * @param resId The text appearance resource id.
- *
- * @attr ref android.R.styleable#DatePicker_dateSelectorDayOfWeekTextAppearance
- */
- public void setDateSelectorDayOfWeekTextAppearance(int resId) {
- mDelegate.setDateSelectorDayOfWeekTextAppearance(resId);
- }
-
- /**
- * Gets the text appearance for the date selector's day of week.
- *
- * @return The text appearance resource id.
- *
- * @attr ref android.R.styleable#DatePicker_dateSelectorDayOfWeekTextAppearance
- */
- public int getDateSelectorDayOfWeekTextAppearance() {
- return mDelegate.getDateSelectorDayOfWeekTextAppearance();
- }
-
- /**
- * Sets the background color for the date selector's.
- *
- * @param color The background color.
- *
- * @attr ref android.R.styleable#DatePicker_dateSelectorBackgroundColor
- */
- public void setDateSelectorBackgroundColor(int color) {
- mDelegate.setDateSelectorBackgroundColor(color);
- }
-
- /**
- * Gets the background color for the date selector's.
- *
- * @return The text appearance resource id.
- *
- * @attr ref android.R.styleable#DatePicker_dateSelectorBackgroundColor
- */
- public int getDateSelectorBackgroundColor() {
- return mDelegate.getDateSelectorBackgroundColor();
- }
-
- /**
- * Sets the text appearance for the date selector's month.
- *
- * @param resId The text appearance resource id.
- *
- * @attr ref android.R.styleable#DatePicker_dateSelectorMonthTextAppearance
- */
- public void setDateSelectorMonthTextAppearance(int resId) {
- mDelegate.setDateSelectorMonthTextAppearance(resId);
- }
-
- /**
- * Gets the text appearance for the date selector's month.
- *
- * @return The text appearance resource id.
- *
- * @attr ref android.R.styleable#DatePicker_dateSelectorMonthTextAppearance
- */
- public int getDateSelectorMonthTextAppearance() {
- return mDelegate.getDateSelectorMonthTextAppearance();
- }
-
- /**
- * Sets the text appearance for the date selector's day of month.
- *
- * @param resId The text appearance resource id.
- *
- * @attr ref android.R.styleable#DatePicker_dateSelectorDayOfMonthTextAppearance
- */
- public void setDateSelectorDayOfMonthTextAppearance(int resId) {
- mDelegate.setDateSelectorDayOfMonthTextAppearance(resId);
- }
-
- /**
- * Gets the text appearance for the date selector's day of month.
- *
- * @return The text appearance resource id.
- *
- * @attr ref android.R.styleable#DatePicker_dateSelectorDayOfMonthTextAppearance
- */
- public int getDateSelectorDayOfMonthTextAppearance() {
- return mDelegate.getDateSelectorDayOfMonthTextAppearance();
- }
-
- /**
- * Sets the text appearance for the date selector's year.
- *
- * @param resId The text appearance resource id.
- *
- * @attr ref android.R.styleable#DatePicker_dateSelectorYearTextAppearance
- */
- public void setDateSelectorYearTextAppearance(int resId) {
- mDelegate.setDateSelectorYearTextAppearance(resId);
- }
-
- /**
- * Gets the text appearance for the date selector's year.
- *
- * @return The text appearance resource id.
- *
- * @attr ref android.R.styleable#DatePicker_dateSelectorYearTextAppearance
- */
- public int getDateSelectorYearTextAppearance() {
- return mDelegate.getDateSelectorYearTextAppearance();
- }
-
- /**
- * Sets the text appearance for the year list item.
- *
- * @param resId The text appearance resource id.
- *
- * @attr ref android.R.styleable#DatePicker_dateSelectorYearListItemTextAppearance
- */
- public void setDateSelectorYearListItemTextAppearance(int resId) {
- mDelegate.setDateSelectorYearListItemTextAppearance(resId);
- }
-
- /**
- * Gets the text appearance for the year list item.
- *
- * @return The text appearance resource id.
- *
- * @attr ref android.R.styleable#DatePicker_dateSelectorYearListItemTextAppearance
- */
- public int getDateSelectorYearListItemTextAppearance() {
- return mDelegate.getDateSelectorYearListItemTextAppearance();
- }
-
- /**
- * Sets the text color state list for the calendar.
- *
- * @param colors The text color state list.
- *
- * @attr ref android.R.styleable#DatePicker_calendarTextColor
- */
- public void setCalendarTextColor(ColorStateList colors) {
- mDelegate.setCalendarTextColor(colors);
- }
-
- /**
- * Gets the text color state list for the calendar.
- *
- * @return The text color state list for the calendar.
- *
- * @attr ref android.R.styleable#DatePicker_calendarTextColor
- */
- public ColorStateList getCalendarTextColor() {
- return mDelegate.getCalendarTextColors();
- }
-
// Override so we are in complete control of save / restore for this widget.
@Override
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
@@ -596,33 +387,6 @@ public class DatePicker extends FrameLayout {
void setEnabled(boolean enabled);
boolean isEnabled();
- void setDateSelectorDayOfWeekBackgroundColor(int color);
- int getDateSelectorDayOfWeekBackgroundColor();
-
- void setDateSelectorDayOfWeekTextAppearance(int resId);
- int getDateSelectorDayOfWeekTextAppearance();
-
- void setDateSelectorBackgroundColor(int color);
- int getDateSelectorBackgroundColor();
-
- void setDateSelectorMonthTextAppearance(int resId);
- int getDateSelectorMonthTextAppearance();
-
- void setDateSelectorDayOfMonthTextAppearance(int resId);
- int getDateSelectorDayOfMonthTextAppearance();
-
- void setDateSelectorYearTextAppearance(int resId);
- int getDateSelectorYearTextAppearance();
-
- void setDateSelectorYearListItemTextAppearance(int resId);
- int getDateSelectorYearListItemTextAppearance();
-
- void setDateSelectorYearListSelectedCircleColor(int color);
- int getDateSelectorYearListSelectedCircleColor();
-
- void setCalendarTextColor(ColorStateList colors);
- ColorStateList getCalendarTextColors();
-
CalendarView getCalendarView();
void setCalendarViewShown(boolean shown);
@@ -979,87 +743,6 @@ public class DatePicker extends FrameLayout {
}
@Override
- public void setDateSelectorDayOfWeekBackgroundColor(int color) {
- }
-
- @Override
- public int getDateSelectorDayOfWeekBackgroundColor() {
- return 0;
- }
-
- @Override
- public void setDateSelectorDayOfWeekTextAppearance(int resId) {
- }
-
- @Override
- public int getDateSelectorDayOfWeekTextAppearance() {
- return 0;
- }
-
- @Override
- public void setDateSelectorBackgroundColor(int color) {
- }
-
- @Override
- public int getDateSelectorBackgroundColor() {
- return 0;
- }
-
- @Override
- public void setDateSelectorMonthTextAppearance(int resId) {
- }
-
- @Override
- public int getDateSelectorMonthTextAppearance() {
- return 0;
- }
-
- @Override
- public void setDateSelectorDayOfMonthTextAppearance(int resId) {
- }
-
- @Override
- public int getDateSelectorDayOfMonthTextAppearance() {
- return 0;
- }
-
- @Override
- public void setDateSelectorYearTextAppearance(int resId) {
- }
-
- @Override
- public int getDateSelectorYearTextAppearance() {
- return 0;
- }
-
- @Override
- public void setDateSelectorYearListItemTextAppearance(int resId) {
- }
-
- @Override
- public int getDateSelectorYearListItemTextAppearance() {
- return 0;
- }
-
- @Override
- public void setDateSelectorYearListSelectedCircleColor(int color) {
- }
-
- @Override
- public int getDateSelectorYearListSelectedCircleColor() {
- return 0;
- }
-
- @Override
- public void setCalendarTextColor(ColorStateList colors) {
- }
-
- @Override
- public ColorStateList getCalendarTextColors() {
- return ColorStateList.valueOf(0);
- }
-
- @Override
public CalendarView getCalendarView() {
return mCalendarView;
}
diff --git a/core/java/android/widget/DatePickerDelegate.java b/core/java/android/widget/DatePickerDelegate.java
index 31044d4..ddc565d 100644
--- a/core/java/android/widget/DatePickerDelegate.java
+++ b/core/java/android/widget/DatePickerDelegate.java
@@ -24,12 +24,14 @@ import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.Color;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.util.SparseArray;
+import android.util.StateSet;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
import android.view.View;
@@ -45,7 +47,6 @@ import com.android.internal.widget.AccessibleDateAnimator;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.Locale;
/**
@@ -76,9 +77,9 @@ class DatePickerDelegate extends DatePicker.AbstractDatePickerDelegate implement
private TextView mDayOfWeekView;
private LinearLayout mDateLayout;
private LinearLayout mMonthAndDayLayout;
- private TextView mSelectedMonthTextView;
- private TextView mSelectedDayTextView;
- private TextView mSelectedYearView;
+ private TextView mHeaderMonthTextView;
+ private TextView mHeaderDayOfMonthTextView;
+ private TextView mHeaderYearTextView;
private DayPickerView mDayPickerView;
private YearPickerView mYearPickerView;
@@ -112,21 +113,8 @@ class DatePickerDelegate extends DatePicker.AbstractDatePickerDelegate implement
private HashSet<OnDateChangedListener> mListeners = new HashSet<OnDateChangedListener>();
- private int mDayOfWeekTextAppearanceResId;
- private int mMonthTextAppearanceResId;
- private int mDayOfMonthTextAppearanceResId;
- private int mYearTextAppearanceResId;
-
- private int mYearListItemTextAppearanceResId;
-
- private int mDayOfWeekBackgroundColor;
- private int mMonthAndDayBackgroundColor;
-
- private ColorStateList mCalendarTextColors;
-
public DatePickerDelegate(DatePicker delegator, Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
-
super(delegator, context);
final Locale locale = Locale.getDefault();
@@ -139,17 +127,14 @@ class DatePickerDelegate extends DatePicker.AbstractDatePickerDelegate implement
mMinDate.set(DEFAULT_START_YEAR, 1, 1);
mMaxDate.set(DEFAULT_END_YEAR, 12, 31);
- // process style attributes
+ final Resources res = mDelegator.getResources();
final TypedArray a = mContext.obtainStyledAttributes(attrs,
R.styleable.DatePicker, defStyleAttr, defStyleRes);
-
final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
-
final int layoutResourceId = a.getResourceId(
R.styleable.DatePicker_internalLayout, R.layout.date_picker_holo);
-
- View mainView = inflater.inflate(layoutResourceId, null);
+ final View mainView = inflater.inflate(layoutResourceId, null);
mDelegator.addView(mainView);
mDayOfWeekView = (TextView) mainView.findViewById(R.id.date_picker_header);
@@ -157,54 +142,68 @@ class DatePickerDelegate extends DatePicker.AbstractDatePickerDelegate implement
mMonthAndDayLayout = (LinearLayout) mainView.findViewById(
R.id.date_picker_month_and_day_layout);
mMonthAndDayLayout.setOnClickListener(this);
- mSelectedMonthTextView = (TextView) mainView.findViewById(R.id.date_picker_month);
- mSelectedDayTextView = (TextView) mainView.findViewById(R.id.date_picker_day);
- mSelectedYearView = (TextView) mainView.findViewById(R.id.date_picker_year);
- mSelectedYearView.setOnClickListener(this);
+ mHeaderMonthTextView = (TextView) mainView.findViewById(R.id.date_picker_month);
+ mHeaderDayOfMonthTextView = (TextView) mainView.findViewById(R.id.date_picker_day);
+ mHeaderYearTextView = (TextView) mainView.findViewById(R.id.date_picker_year);
+ mHeaderYearTextView.setOnClickListener(this);
+
+ // Obtain default highlight color from the theme.
+ final int defaultHighlightColor = mHeaderYearTextView.getHighlightColor();
// Use Theme attributes if possible
- mDayOfWeekTextAppearanceResId = a.getResourceId(
- R.styleable.DatePicker_dateSelectorDayOfWeekTextAppearance, -1);
- if (mDayOfWeekTextAppearanceResId != -1) {
- mDayOfWeekView.setTextAppearance(context, mDayOfWeekTextAppearanceResId);
+ final int dayOfWeekTextAppearanceResId = a.getResourceId(
+ R.styleable.DatePicker_dayOfWeekTextAppearance, -1);
+ if (dayOfWeekTextAppearanceResId != -1) {
+ mDayOfWeekView.setTextAppearance(context, dayOfWeekTextAppearanceResId);
}
- mMonthTextAppearanceResId = a.getResourceId(
- R.styleable.DatePicker_dateSelectorMonthTextAppearance, -1);
- if (mMonthTextAppearanceResId != -1) {
- mSelectedMonthTextView.setTextAppearance(context, mMonthTextAppearanceResId);
- }
+ final int dayOfWeekBackgroundColor = a.getColor(
+ R.styleable.DatePicker_dayOfWeekBackgroundColor, Color.TRANSPARENT);
+ mDayOfWeekView.setBackgroundColor(dayOfWeekBackgroundColor);
- mDayOfMonthTextAppearanceResId = a.getResourceId(
- R.styleable.DatePicker_dateSelectorDayOfMonthTextAppearance, -1);
- if (mDayOfMonthTextAppearanceResId != -1) {
- mSelectedDayTextView.setTextAppearance(context, mDayOfMonthTextAppearanceResId);
- }
+ final int headerSelectedTextColor = a.getColor(
+ R.styleable.DatePicker_headerSelectedTextColor, defaultHighlightColor);
+ final int headerBackgroundColor = a.getColor(R.styleable.DatePicker_headerBackgroundColor,
+ Color.TRANSPARENT);
+ mMonthAndDayLayout.setBackgroundColor(headerBackgroundColor);
- mYearTextAppearanceResId = a.getResourceId(
- R.styleable.DatePicker_dateSelectorYearTextAppearance, -1);
- if (mYearTextAppearanceResId != -1) {
- mSelectedYearView.setTextAppearance(context, mYearTextAppearanceResId);
+ final int monthTextAppearanceResId = a.getResourceId(
+ R.styleable.DatePicker_headerMonthTextAppearance, -1);
+ if (monthTextAppearanceResId != -1) {
+ mHeaderMonthTextView.setTextAppearance(context, monthTextAppearanceResId);
}
+ mHeaderMonthTextView.setTextColor(ColorStateList.addFirstIfMissing(
+ mHeaderMonthTextView.getTextColors(), R.attr.state_selected,
+ headerSelectedTextColor));
- Resources res = mDelegator.getResources();
-
- mDayOfWeekBackgroundColor = a.getColor(
- R.styleable.DatePicker_dateSelectorDayOfWeekBackgroundColor,
- res.getColor(
- R.color.datepicker_default_header_dayofweek_background_color_holo_light));
- mDayOfWeekView.setBackgroundColor(mDayOfWeekBackgroundColor);
+ final int dayOfMonthTextAppearanceResId = a.getResourceId(
+ R.styleable.DatePicker_headerDayOfMonthTextAppearance, -1);
+ if (dayOfMonthTextAppearanceResId != -1) {
+ mHeaderDayOfMonthTextView.setTextAppearance(context, dayOfMonthTextAppearanceResId);
+ }
+ mHeaderDayOfMonthTextView.setTextColor(ColorStateList.addFirstIfMissing(
+ mHeaderDayOfMonthTextView.getTextColors(), R.attr.state_selected,
+ headerSelectedTextColor));
- mMonthAndDayBackgroundColor = a.getColor(R.styleable.DatePicker_dateSelectorBackgroundColor,
- res.getColor(R.color.datepicker_default_header_selector_background_holo_light));
- mMonthAndDayLayout.setBackgroundColor(mMonthAndDayBackgroundColor);
+ final int yearTextAppearanceResId = a.getResourceId(
+ R.styleable.DatePicker_headerYearTextAppearance, -1);
+ if (yearTextAppearanceResId != -1) {
+ mHeaderYearTextView.setTextAppearance(context, yearTextAppearanceResId);
+ }
+ mHeaderYearTextView.setTextColor(ColorStateList.addFirstIfMissing(
+ mHeaderYearTextView.getTextColors(), R.attr.state_selected,
+ headerSelectedTextColor));
mDayPickerView = new DayPickerView(mContext, this);
mYearPickerView = new YearPickerView(mContext);
mYearPickerView.init(this);
- ColorStateList colors = a.getColorStateList(R.styleable.DatePicker_calendarTextColor);
- setCalendarTextColor(colors);
+ final ColorStateList calendarTextColor = a.getColorStateList(
+ R.styleable.DatePicker_calendarTextColor);
+ final int calendarSelectedTextColor = a.getColor(
+ R.styleable.DatePicker_calendarSelectedTextColor, defaultHighlightColor);
+ mDayPickerView.setCalendarTextColor(ColorStateList.addFirstIfMissing(
+ calendarTextColor, R.attr.state_selected, calendarSelectedTextColor));
mDayPickerDescription = res.getString(R.string.day_picker_description);
mSelectDay = res.getString(R.string.select_day);
@@ -308,30 +307,30 @@ class DatePickerDelegate extends DatePicker.AbstractDatePickerDelegate implement
// Restart from a clean state
mMonthAndDayLayout.removeAllViews();
- mDateLayout.removeView(mSelectedYearView);
+ mDateLayout.removeView(mHeaderYearTextView);
// Position the Year View at the correct location
if (viewIndices[YEAR_INDEX] == 0) {
- mDateLayout.addView(mSelectedYearView, 0);
+ mDateLayout.addView(mHeaderYearTextView, 0);
} else {
- mDateLayout.addView(mSelectedYearView, 1);
+ mDateLayout.addView(mHeaderYearTextView, 1);
}
// Position Day and Month Views
if (viewIndices[MONTH_INDEX] > viewIndices[DAY_INDEX]) {
// Day View is first
- mMonthAndDayLayout.addView(mSelectedDayTextView);
- mMonthAndDayLayout.addView(mSelectedMonthTextView);
+ mMonthAndDayLayout.addView(mHeaderDayOfMonthTextView);
+ mMonthAndDayLayout.addView(mHeaderMonthTextView);
} else {
// Month View is first
- mMonthAndDayLayout.addView(mSelectedMonthTextView);
- mMonthAndDayLayout.addView(mSelectedDayTextView);
+ mMonthAndDayLayout.addView(mHeaderMonthTextView);
+ mMonthAndDayLayout.addView(mHeaderDayOfMonthTextView);
}
- mSelectedMonthTextView.setText(mCurrentDate.getDisplayName(Calendar.MONTH, Calendar.SHORT,
+ mHeaderMonthTextView.setText(mCurrentDate.getDisplayName(Calendar.MONTH, Calendar.SHORT,
Locale.getDefault()).toUpperCase(Locale.getDefault()));
- mSelectedDayTextView.setText(mDayFormat.format(mCurrentDate.getTime()));
- mSelectedYearView.setText(mYearFormat.format(mCurrentDate.getTime()));
+ mHeaderDayOfMonthTextView.setText(mDayFormat.format(mCurrentDate.getTime()));
+ mHeaderYearTextView.setText(mYearFormat.format(mCurrentDate.getTime()));
// Accessibility.
long millis = mCurrentDate.getTimeInMillis();
@@ -362,7 +361,7 @@ class DatePickerDelegate extends DatePicker.AbstractDatePickerDelegate implement
mDayPickerView.onDateChanged();
if (mCurrentView != viewIndex) {
mMonthAndDayLayout.setSelected(true);
- mSelectedYearView.setSelected(false);
+ mHeaderYearTextView.setSelected(false);
mAnimator.setDisplayedChild(MONTH_AND_DAY_VIEW);
mCurrentView = viewIndex;
}
@@ -374,7 +373,7 @@ class DatePickerDelegate extends DatePicker.AbstractDatePickerDelegate implement
mAnimator.announceForAccessibility(mSelectDay);
break;
case YEAR_VIEW:
- pulseAnimator = getPulseAnimator(mSelectedYearView, 0.85f, 1.1f);
+ pulseAnimator = getPulseAnimator(mHeaderYearTextView, 0.85f, 1.1f);
if (mDelayAnimation) {
pulseAnimator.setStartDelay(ANIMATION_DELAY);
mDelayAnimation = false;
@@ -382,7 +381,7 @@ class DatePickerDelegate extends DatePicker.AbstractDatePickerDelegate implement
mYearPickerView.onDateChanged();
if (mCurrentView != viewIndex) {
mMonthAndDayLayout.setSelected(false);
- mSelectedYearView.setSelected(true);
+ mHeaderYearTextView.setSelected(true);
mAnimator.setDisplayedChild(YEAR_VIEW);
mCurrentView = viewIndex;
}
@@ -509,7 +508,7 @@ class DatePickerDelegate extends DatePicker.AbstractDatePickerDelegate implement
@Override
public void setEnabled(boolean enabled) {
mMonthAndDayLayout.setEnabled(enabled);
- mSelectedYearView.setEnabled(enabled);
+ mHeaderYearTextView.setEnabled(enabled);
mAnimator.setEnabled(enabled);
mIsEnabled = enabled;
}
@@ -520,123 +519,6 @@ class DatePickerDelegate extends DatePicker.AbstractDatePickerDelegate implement
}
@Override
- public void setDateSelectorDayOfWeekBackgroundColor(int color) {
- if (mDayOfWeekBackgroundColor != color) {
- mDayOfWeekBackgroundColor = color;
- mDayOfWeekView.setBackgroundColor(color);
- }
- }
-
- @Override
- public int getDateSelectorDayOfWeekBackgroundColor() {
- return mDayOfWeekBackgroundColor;
- }
-
- @Override
- public void setDateSelectorDayOfWeekTextAppearance(int resId) {
- if (mDayOfWeekTextAppearanceResId != resId && resId > 0) {
- mDayOfWeekTextAppearanceResId = resId;
- mDayOfWeekView.setTextAppearance(mContext, resId);
- }
- }
-
- @Override
- public int getDateSelectorDayOfWeekTextAppearance() {
- return mDayOfWeekTextAppearanceResId;
- }
-
- @Override
- public void setDateSelectorBackgroundColor(int color) {
- if (mMonthAndDayBackgroundColor != color) {
- mMonthAndDayBackgroundColor = color;
- mMonthAndDayLayout.setBackgroundColor(color);
- }
- }
-
- @Override
- public int getDateSelectorBackgroundColor() {
- return mMonthAndDayBackgroundColor;
- }
-
- @Override
- public void setDateSelectorMonthTextAppearance(int resId) {
- if (mMonthTextAppearanceResId != resId && resId > 0) {
- mMonthTextAppearanceResId = resId;
- mSelectedMonthTextView.setTextAppearance(mContext, resId);
- }
- }
-
- @Override
- public int getDateSelectorMonthTextAppearance() {
- return mMonthTextAppearanceResId;
- }
-
- @Override
- public void setDateSelectorDayOfMonthTextAppearance(int resId) {
- if (mDayOfMonthTextAppearanceResId != resId && resId > 0) {
- mDayOfMonthTextAppearanceResId = resId;
- mSelectedDayTextView.setTextAppearance(mContext, resId);
- }
- }
-
- @Override
- public int getDateSelectorDayOfMonthTextAppearance() {
- return mDayOfMonthTextAppearanceResId;
- }
-
- @Override
- public void setDateSelectorYearTextAppearance(int resId) {
- if (mYearTextAppearanceResId != resId && resId > 0) {
- mYearTextAppearanceResId = resId;
- mSelectedYearView.setTextAppearance(mContext, resId);
- }
- }
-
- @Override
- public int getDateSelectorYearTextAppearance() {
- return mYearTextAppearanceResId;
- }
-
- @Override
- public void setDateSelectorYearListItemTextAppearance(int resId) {
- if (mYearListItemTextAppearanceResId != resId) {
- mYearListItemTextAppearanceResId = resId;
- mYearPickerView.setItemTextAppearance(resId);
- }
- }
-
- @Override
- public int getDateSelectorYearListItemTextAppearance() {
- return mYearListItemTextAppearanceResId;
- }
-
- @Override
- public void setDateSelectorYearListSelectedCircleColor(int color) {
- mYearPickerView.setYearSelectedCircleColor(color);
- }
-
- @Override
- public int getDateSelectorYearListSelectedCircleColor() {
- return mYearPickerView.getYearSelectedCircleColor();
- }
-
- @Override
- public void setCalendarTextColor(ColorStateList colors) {
- if (colors == null) {
- return;
- }
- if (mCalendarTextColors == null || !mCalendarTextColors.equals(colors)) {
- mCalendarTextColors = colors;
- mDayPickerView.setCalendarTextColor(colors);
- }
- }
-
- @Override
- public ColorStateList getCalendarTextColors() {
- return mCalendarTextColors;
- }
-
- @Override
public CalendarView getCalendarView() {
throw new UnsupportedOperationException(
"CalendarView does not exists for the new DatePicker");
@@ -815,9 +697,8 @@ class DatePickerDelegate extends DatePicker.AbstractDatePickerDelegate implement
}
private void updatePickers() {
- Iterator<OnDateChangedListener> iterator = mListeners.iterator();
- while (iterator.hasNext()) {
- iterator.next().onDateChanged();
+ for (OnDateChangedListener listener : mListeners) {
+ listener.onDateChanged();
}
}
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 82e624d..6476cdc 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -156,7 +156,7 @@ public class LinearLayout extends ViewGroup {
equals = Gravity.FILL, name = "FILL"),
@ViewDebug.FlagToString(mask = Gravity.RELATIVE_LAYOUT_DIRECTION,
equals = Gravity.RELATIVE_LAYOUT_DIRECTION, name = "RELATIVE")
- })
+ }, formatToHexString = true)
private int mGravity = Gravity.START | Gravity.TOP;
@ViewDebug.ExportedProperty(category = "measurement")
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 1e30bfa..3d2f67f 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -24,6 +24,7 @@ import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
@@ -104,6 +105,8 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
private static final int CENTER_RADIUS = 2;
+ private static final int[] STATE_SET_SELECTED = new int[] { R.attr.state_selected };
+
private static int[] sSnapPrefer30sMap = new int[361];
private final String[] mHours12Texts = new String[12];
@@ -323,10 +326,20 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
final TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.TimePicker,
defStyle, 0);
- mAmPmUnselectedColor = a.getColor(R.styleable.TimePicker_amPmUnselectedBackgroundColor,
- res.getColor(R.color.timepicker_default_ampm_unselected_background_color_material));
- mAmPmSelectedColor = a.getColor(R.styleable.TimePicker_amPmSelectedBackgroundColor,
+ ColorStateList amPmBackgroundColor = a.getColorStateList(
+ R.styleable.TimePicker_amPmBackgroundColor);
+ if (amPmBackgroundColor == null) {
+ amPmBackgroundColor = res.getColorStateList(
+ R.color.timepicker_default_ampm_unselected_background_color_material);
+ }
+
+ // Obtain the backup selected color. If the background color state
+ // list doesn't have a state for selected, we'll use this color.
+ final int amPmSelectedColor = a.getColor(R.styleable.TimePicker_amPmSelectedBackgroundColor,
res.getColor(R.color.timepicker_default_ampm_selected_background_color_material));
+ mAmPmSelectedColor = amPmBackgroundColor.getColorForState(
+ STATE_SET_SELECTED, amPmSelectedColor);
+ mAmPmUnselectedColor = amPmBackgroundColor.getDefaultColor();
mAmPmTextColor = a.getColor(R.styleable.TimePicker_amPmTextColor,
res.getColor(R.color.timepicker_default_text_color_material));
diff --git a/core/java/android/widget/TextViewWithCircularIndicator.java b/core/java/android/widget/TextViewWithCircularIndicator.java
index 22d770c..43c0843 100644
--- a/core/java/android/widget/TextViewWithCircularIndicator.java
+++ b/core/java/android/widget/TextViewWithCircularIndicator.java
@@ -50,20 +50,18 @@ class TextViewWithCircularIndicator extends TextView {
public TextViewWithCircularIndicator(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
-
super(context, attrs);
- Resources res = context.getResources();
+
// Use Theme attributes if possible
final TypedArray a = mContext.obtainStyledAttributes(attrs,
R.styleable.DatePicker, defStyleAttr, defStyleRes);
-
- final int resId = a.getResourceId(
- R.styleable.DatePicker_dateSelectorYearListItemTextAppearance, -1);
+ final int resId = a.getResourceId(R.styleable.DatePicker_yearListItemTextAppearance, -1);
if (resId != -1) {
setTextAppearance(context, resId);
}
+ final Resources res = context.getResources();
mItemIsSelectedText = res.getString(R.string.item_is_selected);
a.recycle();
diff --git a/core/java/android/widget/TimePickerDelegate.java b/core/java/android/widget/TimePickerDelegate.java
index 45be637..c68619c 100644
--- a/core/java/android/widget/TimePickerDelegate.java
+++ b/core/java/android/widget/TimePickerDelegate.java
@@ -20,6 +20,7 @@ import android.animation.Keyframe;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -79,7 +80,6 @@ class TimePickerDelegate extends TimePicker.AbstractTimePickerDelegate implement
// Duration in ms of the pulse animation
private static final int PULSE_ANIMATOR_DURATION = 544;
- private final View mMainView;
private TextView mHourView;
private TextView mMinuteView;
private TextView mAmPmTextView;
@@ -88,8 +88,6 @@ class TimePickerDelegate extends TimePicker.AbstractTimePickerDelegate implement
private ViewGroup mLayoutButtons;
- private int mHeaderSelectedColor;
- private int mHeaderUnselectedColor;
private String mAmText;
private String mPmText;
@@ -128,7 +126,8 @@ class TimePickerDelegate extends TimePicker.AbstractTimePickerDelegate implement
// process style attributes
final TypedArray a = mContext.obtainStyledAttributes(attrs,
R.styleable.TimePicker, defStyleAttr, defStyleRes);
-
+ final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
final Resources res = mContext.getResources();
mHourPickerDescription = res.getString(R.string.hour_picker_description);
@@ -136,53 +135,52 @@ class TimePickerDelegate extends TimePicker.AbstractTimePickerDelegate implement
mMinutePickerDescription = res.getString(R.string.minute_picker_description);
mSelectMinutes = res.getString(R.string.select_minutes);
- mHeaderSelectedColor = a.getColor(R.styleable.TimePicker_headerSelectedTextColor,
- res.getColor(R.color.timepicker_default_selector_color_material));
-
- final int headerTimeTextAppearance = a.getResourceId(
- R.styleable.TimePicker_headerTimeTextAppearance, 0);
- final int headerAmPmTextAppearance = a.getResourceId(
- R.styleable.TimePicker_headerAmPmTextAppearance, 0);
- final int headerBackgroundColor = a.getColor(
- R.styleable.TimePicker_headerBackgroundColor, Color.TRANSPARENT);
- final int layoutResourceId = a.getResourceId(
- R.styleable.TimePicker_internalLayout, R.layout.time_picker_holo);
-
- a.recycle();
-
- final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
-
- mMainView = inflater.inflate(layoutResourceId, null);
- mDelegator.addView(mMainView);
+ final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout,
+ R.layout.time_picker_holo);
+ final View mainView = inflater.inflate(layoutResourceId, null);
+ mDelegator.addView(mainView);
- mHourView = (TextView) mMainView.findViewById(R.id.hours);
- mSeparatorView = (TextView) mMainView.findViewById(R.id.separator);
- mMinuteView = (TextView) mMainView.findViewById(R.id.minutes);
- mAmPmTextView = (TextView) mMainView.findViewById(R.id.ampm_label);
- mLayoutButtons = (ViewGroup) mMainView.findViewById(R.id.layout_buttons);
+ mHourView = (TextView) mainView.findViewById(R.id.hours);
+ mSeparatorView = (TextView) mainView.findViewById(R.id.separator);
+ mMinuteView = (TextView) mainView.findViewById(R.id.minutes);
+ mAmPmTextView = (TextView) mainView.findViewById(R.id.ampm_label);
+ mLayoutButtons = (ViewGroup) mainView.findViewById(R.id.layout_buttons);
// Set up text appearances from style.
+ final int headerTimeTextAppearance = a.getResourceId(
+ R.styleable.TimePicker_headerTimeTextAppearance, 0);
if (headerTimeTextAppearance != 0) {
mHourView.setTextAppearance(context, headerTimeTextAppearance);
mSeparatorView.setTextAppearance(context, headerTimeTextAppearance);
mMinuteView.setTextAppearance(context, headerTimeTextAppearance);
}
+ final int headerSelectedTextColor = a.getColor(
+ R.styleable.TimePicker_headerSelectedTextColor,
+ res.getColor(R.color.timepicker_default_selector_color_material));
+ mHourView.setTextColor(ColorStateList.addFirstIfMissing(mHourView.getTextColors(),
+ R.attr.state_selected, headerSelectedTextColor));
+ mMinuteView.setTextColor(ColorStateList.addFirstIfMissing(mMinuteView.getTextColors(),
+ R.attr.state_selected, headerSelectedTextColor));
+
+ final int headerAmPmTextAppearance = a.getResourceId(
+ R.styleable.TimePicker_headerAmPmTextAppearance, 0);
if (headerAmPmTextAppearance != 0) {
mAmPmTextView.setTextAppearance(context, headerAmPmTextAppearance);
}
+ final int headerBackgroundColor = a.getColor(
+ R.styleable.TimePicker_headerBackgroundColor, Color.TRANSPARENT);
if (headerBackgroundColor != Color.TRANSPARENT) {
mLayoutButtons.setBackgroundColor(headerBackgroundColor);
- mMainView.findViewById(R.id.time_header).setBackgroundColor(headerBackgroundColor);
+ mainView.findViewById(R.id.time_header).setBackgroundColor(headerBackgroundColor);
}
- // Load unselected header color from current state.
- mHeaderUnselectedColor = mHourView.getCurrentTextColor();
+ a.recycle();
- mRadialTimePickerView = (RadialTimePickerView) mMainView.findViewById(R.id.radial_picker);
- mDoneButton = (Button) mMainView.findViewById(R.id.done_button);
+ mRadialTimePickerView = (RadialTimePickerView) mainView.findViewById(
+ R.id.radial_picker);
+ mDoneButton = (Button) mainView.findViewById(R.id.done_button);
String[] amPmTexts = new DateFormatSymbols().getAmPmStrings();
mAmText = amPmTexts[0];
@@ -785,7 +783,6 @@ class TimePickerDelegate extends TimePicker.AbstractTimePickerDelegate implement
separatorText = Character.toString(bestDateTimePattern.charAt(hIndex + 1));
}
mSeparatorView.setText(separatorText);
- mSeparatorView.setTextColor(mHeaderUnselectedColor);
}
static private int lastIndexOfAny(String str, char[] any) {
@@ -839,10 +836,8 @@ class TimePickerDelegate extends TimePicker.AbstractTimePickerDelegate implement
labelToAnimate = mMinuteView;
}
- int hourColor = (index == HOUR_INDEX) ? mHeaderSelectedColor : mHeaderUnselectedColor;
- int minuteColor = (index == MINUTE_INDEX) ? mHeaderSelectedColor : mHeaderUnselectedColor;
- mHourView.setTextColor(hourColor);
- mMinuteView.setTextColor(minuteColor);
+ mHourView.setSelected(index == HOUR_INDEX);
+ mMinuteView.setSelected(index == MINUTE_INDEX);
ObjectAnimator pulseAnimator = getPulseAnimator(labelToAnimate, 0.85f, 1.1f);
if (delayLabelAnimate) {
@@ -1064,9 +1059,9 @@ class TimePickerDelegate extends TimePicker.AbstractTimePickerDelegate implement
String minuteStr = (values[1] == -1) ? mDoublePlaceholderText :
String.format(minuteFormat, values[1]).replace(' ', mPlaceholderText);
mHourView.setText(hourStr);
- mHourView.setTextColor(mHeaderUnselectedColor);
+ mHourView.setSelected(false);
mMinuteView.setText(minuteStr);
- mMinuteView.setTextColor(mHeaderUnselectedColor);
+ mMinuteView.setSelected(false);
if (!mIs24HourView) {
updateAmPmDisplay(values[2]);
}
@@ -1143,8 +1138,7 @@ class TimePickerDelegate extends TimePicker.AbstractTimePickerDelegate implement
}
}
- int[] ret = {hour, minute, amOrPm};
- return ret;
+ return new int[] { hour, minute, amOrPm };
}
/**
diff --git a/core/java/android/widget/YearPickerView.java b/core/java/android/widget/YearPickerView.java
index bac9320..b67fa55 100644
--- a/core/java/android/widget/YearPickerView.java
+++ b/core/java/android/widget/YearPickerView.java
@@ -33,8 +33,6 @@ import com.android.internal.R;
*/
class YearPickerView extends ListView implements AdapterView.OnItemClickListener,
OnDateChangedListener {
- private static final String TAG = "YearPickerView";
-
private DatePickerController mController;
private YearAdapter mAdapter;
private int mViewSize;
@@ -57,11 +55,11 @@ class YearPickerView extends ListView implements AdapterView.OnItemClickListener
public YearPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- ViewGroup.LayoutParams frame = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT,
- LayoutParams.WRAP_CONTENT);
+ final LayoutParams frame = new LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
setLayoutParams(frame);
- Resources res = context.getResources();
+ final Resources res = context.getResources();
mViewSize = res.getDimensionPixelOffset(R.dimen.datepicker_view_animator_height);
mChildSize = res.getDimensionPixelOffset(R.dimen.datepicker_year_label_height);
@@ -73,11 +71,9 @@ class YearPickerView extends ListView implements AdapterView.OnItemClickListener
setPadding(0, paddingTop, 0, 0);
// Use Theme attributes if possible
- final TypedArray a = context.obtainStyledAttributes(attrs,
- R.styleable.DatePicker, defStyleAttr, defStyleRes);
-
- final int colorResId = a.getResourceId(
- R.styleable.DatePicker_dateSelectorYearListSelectedCircleColor,
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.DatePicker, defStyleAttr, defStyleRes);
+ final int colorResId = a.getResourceId(R.styleable.DatePicker_yearListSelectorColor,
R.color.datepicker_default_circle_background_color_holo_light);
mYearSelectedCircleColor = res.getColor(colorResId);
diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp
index 2ad8330..b3ed6f0 100644
--- a/core/jni/android/graphics/MinikinUtils.cpp
+++ b/core/jni/android/graphics/MinikinUtils.cpp
@@ -44,25 +44,25 @@ void MinikinUtils::doLayout(Layout* layout, const Paint* paint, int bidiFlags, T
const uint16_t* buf, size_t start, size_t count, size_t bufSize) {
TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface);
layout->setFontCollection(resolvedFace->fFontCollection);
- FontStyle style = resolvedFace->fStyle;
- char css[512];
- int off = snprintfcat(css, 0, sizeof(css),
- "font-size: %d; font-scale-x: %f; font-skew-x: %f; -paint-flags: %d;"
- " font-weight: %d; font-style: %s; -minikin-bidi: %d; letter-spacing: %f;",
- (int)paint->getTextSize(),
- paint->getTextScaleX(),
- paint->getTextSkewX(),
- MinikinFontSkia::packPaintFlags(paint),
- style.getWeight() * 100,
- style.getItalic() ? "italic" : "normal",
- bidiFlags,
- paint->getLetterSpacing());
- SkString langString = paint->getPaintOptionsAndroid().getLanguage().getTag();
- off = snprintfcat(css, off, sizeof(css), " lang: %s;", langString.c_str());
+ FontStyle resolved = resolvedFace->fStyle;
+
+ /* Prepare minikin FontStyle */
+ SkString langStr = paint->getPaintOptionsAndroid().getLanguage().getTag();
+ FontLanguage minikinLang(langStr.c_str(), langStr.size());
SkPaintOptionsAndroid::FontVariant var = paint->getPaintOptionsAndroid().getFontVariant();
- const char* varstr = var == SkPaintOptionsAndroid::kElegant_Variant ? "elegant" : "compact";
- off = snprintfcat(css, off, sizeof(css), " -minikin-variant: %s;", varstr);
- layout->doLayout(buf, start, count, bufSize, std::string(css));
+ FontVariant minikinVariant = var == SkPaintOptionsAndroid::kElegant_Variant ? VARIANT_ELEGANT
+ : VARIANT_COMPACT;
+ FontStyle minikinStyle(minikinLang, minikinVariant, resolved.getWeight(), resolved.getItalic());
+
+ /* Prepare minikin Paint */
+ MinikinPaint minikinPaint;
+ minikinPaint.size = (int)/*WHY?!*/paint->getTextSize();
+ minikinPaint.scaleX = paint->getTextScaleX();
+ minikinPaint.skewX = paint->getTextSkewX();
+ minikinPaint.letterSpacing = paint->getLetterSpacing();
+ minikinPaint.paintFlags = MinikinFontSkia::packPaintFlags(paint);
+
+ layout->doLayout(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint);
}
float MinikinUtils::xOffsetForTextAlign(Paint* paint, const Layout& layout) {
diff --git a/core/res/res/color/date_picker_calendar_material_dark.xml b/core/res/res/color/date_picker_calendar_material_dark.xml
deleted file mode 100644
index 86a0673..0000000
--- a/core/res/res/color/date_picker_calendar_material_dark.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item android:state_enabled="true" android:state_selected="false"
- android:color="@color/datepicker_default_normal_text_color_material_dark"/>
- <item android:state_enabled="true" android:state_selected="true"
- android:color="@color/holo_blue_light"/>
- <item android:state_enabled="false"
- android:color="@color/datepicker_default_disabled_text_color_material_dark"/>
-
-</selector> \ No newline at end of file
diff --git a/core/res/res/color/date_picker_calendar_material_light.xml b/core/res/res/color/date_picker_calendar_material_light.xml
deleted file mode 100644
index 015eed7..0000000
--- a/core/res/res/color/date_picker_calendar_material_light.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item android:state_enabled="true" android:state_selected="false"
- android:color="@color/datepicker_default_normal_text_color_material_light"/>
- <item android:state_enabled="true" android:state_selected="true"
- android:color="@color/holo_blue_light"/>
- <item android:state_enabled="false"
- android:color="@color/datepicker_default_disabled_text_color_material_light"/>
-
-</selector> \ No newline at end of file
diff --git a/core/res/res/color/date_picker_selector_material_dark.xml b/core/res/res/color/date_picker_selector_material_dark.xml
deleted file mode 100644
index e407387..0000000
--- a/core/res/res/color/date_picker_selector_material_dark.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item android:state_pressed="true"
- android:color="@color/datepicker_default_pressed_text_color_material_dark"/>
- <item android:state_pressed="false" android:state_selected="true"
- android:color="@color/datepicker_default_selected_text_color_material_dark"/>
- <item android:state_pressed="false" android:state_selected="false"
- android:color="@color/datepicker_default_normal_text_color_material_dark"/>
-
-</selector> \ No newline at end of file
diff --git a/core/res/res/color/date_picker_selector_material_light.xml b/core/res/res/color/date_picker_selector_material_light.xml
deleted file mode 100644
index b4c6a47..0000000
--- a/core/res/res/color/date_picker_selector_material_light.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item android:state_pressed="true"
- android:color="@color/datepicker_default_pressed_text_color_material_light"/>
- <item android:state_pressed="false" android:state_selected="true"
- android:color="@color/datepicker_default_selected_text_color_material_light"/>
- <item android:state_pressed="false" android:state_selected="false"
- android:color="@color/datepicker_default_normal_text_color_material_light"/>
-
-</selector> \ No newline at end of file
diff --git a/core/res/res/color/date_picker_year_selector_material_dark.xml b/core/res/res/color/date_picker_year_selector_material_dark.xml
deleted file mode 100644
index b5ff09a..0000000
--- a/core/res/res/color/date_picker_year_selector_material_dark.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item android:state_pressed="true"
- android:color="@color/datepicker_default_pressed_text_color_material_dark"/>
- <item android:state_pressed="false" android:state_selected="false"
- android:color="@color/datepicker_default_normal_text_color_material_dark"/>
-
-</selector> \ No newline at end of file
diff --git a/core/res/res/color/date_picker_year_selector_material_light.xml b/core/res/res/color/date_picker_year_selector_material_light.xml
deleted file mode 100644
index 5e329b3..0000000
--- a/core/res/res/color/date_picker_year_selector_material_light.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item android:state_pressed="true"
- android:color="@color/datepicker_default_pressed_text_color_material_light"/>
- <item android:state_pressed="false" android:state_selected="false"
- android:color="@color/datepicker_default_normal_text_color_material_light"/>
-
-</selector> \ No newline at end of file
diff --git a/core/res/res/layout-land/date_picker_holo.xml b/core/res/res/layout-land/date_picker_holo.xml
index 98e26ca..af8f598 100644
--- a/core/res/res/layout-land/date_picker_holo.xml
+++ b/core/res/res/layout-land/date_picker_holo.xml
@@ -24,7 +24,6 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
- android:background="?android:attr/datePickerHeaderSelectorBackgroundColor"
android:orientation="vertical" >
<LinearLayout
diff --git a/core/res/res/layout/date_picker_header_view.xml b/core/res/res/layout/date_picker_header_view.xml
index eccdd3e..66d5e1b 100644
--- a/core/res/res/layout/date_picker_header_view.xml
+++ b/core/res/res/layout/date_picker_header_view.xml
@@ -18,9 +18,6 @@
android:id="@+id/date_picker_header"
android:layout_width="@dimen/datepicker_component_width"
android:layout_height="@dimen/datepicker_header_height"
- android:background="?android:attr/datePickerHeaderDayOfWeekLabelBackgroundColor"
android:gravity="center"
- android:textAppearance="?android:attr/datePickerHeaderDayOfWeekLabelTextAppearance"
android:importantForAccessibility="no"
- android:textAllCaps="true"
- />
+ android:textAllCaps="true" />
diff --git a/core/res/res/layout/date_picker_holo.xml b/core/res/res/layout/date_picker_holo.xml
index 389c2b5..1199a72 100644
--- a/core/res/res/layout/date_picker_holo.xml
+++ b/core/res/res/layout/date_picker_holo.xml
@@ -18,12 +18,12 @@
android:layout_width="@dimen/datepicker_component_width"
android:layout_height="match_parent"
android:gravity="center"
- android:orientation="vertical" >
+ android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="vertical" >
+ android:orientation="vertical">
<include layout="@layout/date_picker_header_view" />
@@ -34,4 +34,4 @@
<include layout="@layout/date_picker_done_button" />
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/core/res/res/layout/date_picker_selected_date.xml b/core/res/res/layout/date_picker_selected_date.xml
index 426deed..c5afddc 100644
--- a/core/res/res/layout/date_picker_selected_date.xml
+++ b/core/res/res/layout/date_picker_selected_date.xml
@@ -22,9 +22,8 @@
android:layout_weight="1"
android:paddingTop="8dip"
android:paddingBottom="8dip"
- android:background="?android:attr/datePickerHeaderSelectorBackgroundColor"
android:gravity="center"
- android:orientation="vertical" >
+ android:orientation="vertical">
<LinearLayout
android:id="@+id/date_picker_month_and_day_layout"
@@ -32,15 +31,14 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:clickable="true"
- android:orientation="vertical" >
+ android:orientation="vertical">
<TextView
android:id="@+id/date_picker_month"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:duplicateParentState="true"
- android:gravity="center_horizontal|bottom"
- android:textAppearance="?android:attr/datePickerHeaderSelectorMonthLabelTextAppearance" />
+ android:gravity="center_horizontal|bottom" />
<TextView
android:id="@+id/date_picker_day"
@@ -50,8 +48,7 @@
android:layout_marginBottom="-10dip"
android:layout_marginTop="-10dip"
android:duplicateParentState="true"
- android:gravity="center"
- android:textAppearance="?android:attr/datePickerHeaderSelectorDayOfMonthLabelTextAppearance" />
+ android:gravity="center" />
</LinearLayout>
<TextView
@@ -59,7 +56,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:gravity="center_horizontal|top"
- android:textAppearance="?android:attr/datePickerHeaderSelectorYearLabelTextAppearance" />
+ android:gravity="center_horizontal|top" />
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/core/res/res/layout/year_label_text_view.xml b/core/res/res/layout/year_label_text_view.xml
index 4e39831..e5bd068 100644
--- a/core/res/res/layout/year_label_text_view.xml
+++ b/core/res/res/layout/year_label_text_view.xml
@@ -19,5 +19,4 @@
android:layout_width="match_parent"
android:layout_height="@dimen/datepicker_year_label_height"
android:layout_gravity="center"
- android:gravity="center"
- android:textAppearance="?android:attr/datePickerHeaderListYearLabelTextAppearance" />
+ android:gravity="center" />
diff --git a/core/res/res/values-television/themes.xml b/core/res/res/values-television/themes.xml
index 3333f1b..f92ff40 100644
--- a/core/res/res/values-television/themes.xml
+++ b/core/res/res/values-television/themes.xml
@@ -16,13 +16,8 @@
<resources>
<style name="Theme.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
<style name="Theme.Dialog.AppError" parent="Theme.Leanback.Dialog.AppError" />
- <style name="Theme.Dialog.TimePicker" parent="Theme.Leanback.Dialog.TimePicker" />
<style name="Theme.Holo.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
- <style name="Theme.Holo.Dialog.TimePicker" parent="Theme.Leanback.Dialog.TimePicker" />
<style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
- <style name="Theme.Holo.Light.Dialog.TimePicker" parent="Theme.Leanback.Light.Dialog.TimePicker" />
<style name="Theme.Material.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
- <style name="Theme.Material.Dialog.TimePicker" parent="Theme.Leanback.Dialog.TimePicker" />
<style name="Theme.Material.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
- <style name="Theme.Material.Light.Dialog.TimePicker" parent="Theme.Leanback.Light.Dialog.TimePicker" />
</resources>
diff --git a/core/res/res/values-television/themes_device_defaults.xml b/core/res/res/values-television/themes_device_defaults.xml
index 1938675..e01caa3 100644
--- a/core/res/res/values-television/themes_device_defaults.xml
+++ b/core/res/res/values-television/themes_device_defaults.xml
@@ -16,6 +16,4 @@
<resources>
<style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
<style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
- <style name="Theme.DeviceDefault.Dialog.TimePicker" parent="Theme.Leanback.Dialog.TimePicker" />
- <style name="Theme.DeviceDefault.Light.Dialog.TimePicker" parent="Theme.Leanback.Light.Dialog.TimePicker" />
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 82a75b5..870f7ec 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -682,30 +682,6 @@
<!-- The DatePicker style. -->
<attr name="datePickerStyle" format="reference" />
- <!-- The DatePicker Header day of week label background color . -->
- <attr name="datePickerHeaderDayOfWeekLabelBackgroundColor" format="reference" />
-
- <!-- The DatePicker Header day of week label text appearance -->
- <attr name="datePickerHeaderDayOfWeekLabelTextAppearance" format="reference" />
-
- <!-- The DatePicker Header selector background color . -->
- <attr name="datePickerHeaderSelectorBackgroundColor" format="reference" />
-
- <!-- The DatePicker Header selector month label text appearance -->
- <attr name="datePickerHeaderSelectorMonthLabelTextAppearance" format="reference" />
-
- <!-- The DatePicker Header selector day of month label text appearance -->
- <attr name="datePickerHeaderSelectorDayOfMonthLabelTextAppearance" format="reference" />
-
- <!-- The DatePicker Header selector year label text appearance -->
- <attr name="datePickerHeaderSelectorYearLabelTextAppearance" format="reference" />
-
- <!-- The DatePicker Header list year label text appearance -->
- <attr name="datePickerHeaderListYearLabelTextAppearance" format="reference" />
-
- <!-- DatePicker list year label circle background color -->
- <attr name="datePickerHeaderListYearLabelCircleBackgroundColor" format="reference" />
-
<!-- The DatePicker dialog theme. -->
<attr name="datePickerDialogTheme" format="reference" />
@@ -4215,12 +4191,10 @@
<declare-styleable name="DatePicker">
<!-- The first year (inclusive), for example "1940".
- {@deprecated Use minDate instead.}
- -->
+ {@deprecated Use minDate instead.} -->
<attr name="startYear" format="integer" />
<!-- The last year (inclusive), for example "2010".
- {@deprecated Use maxDate instead.}
- -->
+ {@deprecated Use maxDate instead.} -->
<attr name="endYear" format="integer" />
<!-- Whether the spinners are shown. -->
<attr name="spinnersShown" format="boolean" />
@@ -4236,24 +4210,32 @@
<attr name="legacyLayout" />
<!-- @hide Enables or disable the use of the legacy layout for the DatePicker. -->
<attr name="legacyMode" />
- <!-- The background color for the date selector 's day of week of the non legacy DatePicker. -->
- <attr name="dateSelectorDayOfWeekBackgroundColor" format="color|reference" />
- <!-- The text color for the date selector's day of week of the non legacy DatePicker. -->
- <attr name="dateSelectorDayOfWeekTextAppearance" format="reference" />
- <!-- The background color for the date selector of the non legacy DatePicker. -->
- <attr name="dateSelectorBackgroundColor" format="color|reference" />
- <!-- The month's text appearance in the date selector of the non legacy DatePicker. -->
- <attr name="dateSelectorMonthTextAppearance" format="reference" />
- <!-- The day of month's text appearance in the date selector of the non legacy DatePicker. -->
- <attr name="dateSelectorDayOfMonthTextAppearance" format="reference" />
- <!-- The year's text appearance in the date selector of the non legacy DatePicker. -->
- <attr name="dateSelectorYearTextAppearance" format="reference" />
- <!-- The list year's text appearance in the list of the non legacy DatePicker. -->
- <attr name="dateSelectorYearListItemTextAppearance" format="reference" />
- <!-- The list year's selected circle color in the list of the non legacy DatePicker. -->
- <attr name="dateSelectorYearListSelectedCircleColor" format="color|reference" />
- <!-- The text color list of the calendar of the non legacy DatePicker. -->
- <attr name="calendarTextColor" format="color|reference" />
+ <!-- The background color for the date selector 's day of week. -->
+ <attr name="dayOfWeekBackgroundColor" format="color" />
+ <!-- The text color for the date selector's day of week. -->
+ <attr name="dayOfWeekTextAppearance" format="reference" />
+ <!-- The month's text appearance in the date selector. -->
+ <attr name="headerMonthTextAppearance" format="reference" />
+ <!-- The day of month's text appearance in the date selector. -->
+ <attr name="headerDayOfMonthTextAppearance" format="reference" />
+ <!-- The year's text appearance in the date selector. -->
+ <attr name="headerYearTextAppearance" format="reference" />
+ <!-- The background color for the date selector. -->
+ <attr name="headerBackgroundColor" />
+ <!-- @hide The selected text color for the date selector. Used as a
+ backup if the text appearance does not explicitly have a color
+ set for the selected state. -->
+ <attr name="headerSelectedTextColor" />
+ <!-- The list year's text appearance in the list. -->
+ <attr name="yearListItemTextAppearance" format="reference" />
+ <!-- The list year's selected circle color in the list. -->
+ <attr name="yearListSelectorColor" format="color" />
+ <!-- The text color list of the calendar. -->
+ <attr name="calendarTextColor" format="color" />
+ <!-- @hide The selected text color for the calendar. Used as a backup
+ if the text color does not explicitly have a color set for the
+ selected state. -->
+ <attr name="calendarSelectedTextColor" format="color" />
</declare-styleable>
<declare-styleable name="TwoLineListItem">
@@ -4533,8 +4515,9 @@
<attr name="headerAmPmTextAppearance" format="reference" />
<!-- The text appearance for the time header of the TimePicker. -->
<attr name="headerTimeTextAppearance" format="reference" />
- <!-- The text color for selected time header of the TimePicker. This
- will override the value from the text appearance. -->
+ <!-- @hide The text color for selected time header of the TimePicker.
+ This will override the value from the text appearance if it does
+ not explicitly have a color set for the selected state. -->
<attr name="headerSelectedTextColor" format="color" />
<!-- The background color for the header of the TimePicker. -->
<attr name="headerBackgroundColor" format="color" />
@@ -4544,9 +4527,11 @@
<attr name="numbersBackgroundColor" format="color" />
<!-- The color for the AM/PM selectors of the TimePicker. -->
<attr name="amPmTextColor" format="color" />
- <!-- The background color for the AM/PM selectors of the TimePicker when unselected. -->
- <attr name="amPmUnselectedBackgroundColor" format="color" />
- <!-- The background color for the AM/PM selectors of the TimePicker when selected. -->
+ <!-- The background color state list for the AM/PM selectors of the TimePicker. -->
+ <attr name="amPmBackgroundColor" format="color" />
+ <!-- @hide The background color for the AM/PM selectors of the
+ TimePicker when selected. Used if the background color does not
+ explicitly have a color set for the selected state. -->
<attr name="amPmSelectedBackgroundColor" format="color" />
<!-- The color for the hours/minutes selector of the TimePicker. -->
<attr name="numbersSelectorColor" format="color" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c71036e..88cf7c8 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2237,38 +2237,33 @@
<public type="attr" name="windowElevation" />
<public type="attr" name="launchTaskBehindBackgroundAnimation" />
<public type="attr" name="launchTaskBehindSourceAnimation" />
- <!-- Attribute specified in a restriction entry to denote the type of restriction. -->
<public type="attr" name="restrictionType" />
- <!-- For the DatePicker -->
- <public type="attr" name="dateSelectorDayOfWeekBackgroundColor" />
- <public type="attr" name="dateSelectorDayOfWeekTextAppearance" />
- <public type="attr" name="dateSelectorBackgroundColor" />
- <public type="attr" name="dateSelectorMonthTextAppearance" />
- <public type="attr" name="dateSelectorDayOfMonthTextAppearance" />
- <public type="attr" name="dateSelectorYearTextAppearance" />
- <public type="attr" name="dateSelectorYearListItemTextAppearance" />
- <public type="attr" name="dateSelectorYearListSelectedCircleColor" />
+ <public type="attr" name="dayOfWeekBackgroundColor" />
+ <public type="attr" name="dayOfWeekTextAppearance" />
+ <public type="attr" name="headerMonthTextAppearance" />
+ <public type="attr" name="headerDayOfMonthTextAppearance" />
+ <public type="attr" name="headerYearTextAppearance" />
+ <public type="attr" name="yearListItemTextAppearance" />
+ <public type="attr" name="yearListSelectorColor" />
<public type="attr" name="calendarTextColor" />
<public type="attr" name="recognitionService" />
- <!-- For the TimePicker -->
<public type="attr" name="timePickerStyle" />
<public type="attr" name="timePickerDialogTheme" />
<public type="attr" name="headerTimeTextAppearance" />
<public type="attr" name="headerAmPmTextAppearance" />
- <public type="attr" name="headerSelectedTextColor" />
<public type="attr" name="headerBackgroundColor" />
<public type="attr" name="numbersTextColor" />
<public type="attr" name="numbersBackgroundColor" />
<public type="attr" name="numbersSelectorColor" />
<public type="attr" name="amPmTextColor" />
- <public type="attr" name="amPmUnselectedBackgroundColor" />
- <public type="attr" name="amPmSelectedBackgroundColor" />
+ <public type="attr" name="amPmBackgroundColor" />
<public type="attr" name="searchKeyphraseRecognitionFlags" />
<public type="attr" name="checkMarkTint" />
<public type="attr" name="checkMarkTintMode" />
<public type="attr" name="popupTheme" />
<public type="attr" name="toolbarStyle" />
<public type="attr" name="windowClipToOutline" />
+ <public type="attr" name="datePickerDialogTheme" />
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 2dccaf2..4a70952 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -573,7 +573,8 @@ please see styles_device_defaults.xml.
</style>
<style name="Widget.DatePicker">
- <item name="legacyLayout">@android:layout/date_picker_legacy</item>
+ <item name="legacyMode">true</item>
+ <item name="legacyLayout">@layout/date_picker_legacy</item>
<item name="calendarViewShown">false</item>
</style>
@@ -947,9 +948,9 @@ please see styles_device_defaults.xml.
</style>
<style name="PreferenceFragment">
- <item name="android:layout">@android:layout/preference_list_fragment</item>
- <item name="android:paddingStart">0dp</item>
- <item name="android:paddingEnd">0dp</item>
+ <item name="layout">@layout/preference_list_fragment</item>
+ <item name="paddingStart">0dp</item>
+ <item name="paddingEnd">0dp</item>
</style>
<style name="Preference.Information">
@@ -1333,9 +1334,6 @@ please see styles_device_defaults.xml.
<item name="orientation">vertical</item>
</style>
- <style name="TextAppearance.TimePicker.TimeLabel" parent="TextAppearance" />
- <style name="TextAppearance.TimePicker.AmPmLabel" parent="TextAppearance" />
-
<style name="Widget.FastScroll">
<item name="thumbDrawable">?attr/fastScrollThumbDrawable</item>
<item name="trackDrawable">?attr/fastScrollTrackDrawable</item>
@@ -1359,22 +1357,4 @@ please see styles_device_defaults.xml.
<item name="spotShadowAlpha">0.1765</item>
</style>
- <style name="TextAppearance.DatePicker.DayOfWeekLabel" parent="TextAppearance">
- </style>
-
- <style name="TextAppearance.DatePicker.Selector" parent="TextAppearance">
- </style>
-
- <style name="TextAppearance.DatePicker.Selector.MonthLabel" parent="TextAppearance.DatePicker.Selector">
- </style>
-
- <style name="TextAppearance.DatePicker.Selector.DayOfMonthLabel" parent="TextAppearance.DatePicker.Selector">
- </style>
-
- <style name="TextAppearance.DatePicker.Selector.YearLabel" parent="TextAppearance.DatePicker.Selector">
- </style>
-
- <style name="TextAppearance.DatePicker.List.YearLabel" parent="TextAppearance">
- </style>
-
</resources>
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index fb8d9f5..223578d 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -240,6 +240,10 @@ easier.
<!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
<style name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle.Inverse" parent="TextAppearance.Material.Widget.ActionMode.Subtitle.Inverse"/>
<style name="TextAppearance.DeviceDefault.Widget.ActionBar.Menu" parent="TextAppearance.Material.Widget.ActionBar.Menu"/>
+ <style name="TextAppearance.DeviceDefault.DatePicker.DayOfWeekLabel" parent="TextAppearance.Material.DatePicker.DayOfWeekLabel"/>
+ <style name="TextAppearance.DeviceDefault.DatePicker.MonthLabel" parent="TextAppearance.Material.DatePicker.MonthLabel"/>
+ <style name="TextAppearance.DeviceDefault.DatePicker.DayOfMonthLabel" parent="TextAppearance.Material.DatePicker.DayOfMonthLabel"/>
+ <style name="TextAppearance.DeviceDefault.DatePicker.YearLabel" parent="TextAppearance.Material.DatePicker.YearLabel"/>
<!-- Preference Styles -->
<style name="Preference.DeviceDefault" parent="Preference.Material"/>
@@ -279,25 +283,4 @@ easier.
<style name="DeviceDefault.Light.ButtonBar.AlertDialog" parent="Widget.Material.Light.ButtonBar.AlertDialog"/>
<style name="DeviceDefault.Light.SegmentedButton" parent="Widget.Material.Light.SegmentedButton"/>
- <style name="Theme.DeviceDefault.Dialog.TimePicker" parent="Theme.Material.Dialog.TimePicker"/>
- <style name="Theme.DeviceDefault.Light.Dialog.TimePicker" parent="Theme.Material.Light.Dialog.TimePicker"/>
-
- <style name="TextAppearance.DeviceDefault.DatePicker.DayOfWeekLabel" parent="TextAppearance.Material.DatePicker.DayOfWeekLabel"/>
- <style name="TextAppearance.DeviceDefault.Light.DatePicker.DayOfWeekLabel" parent="TextAppearance.Material.Light.DatePicker.DayOfWeekLabel"/>
-
- <style name="TextAppearance.DeviceDefault.DatePicker.Selector" parent="TextAppearance.Material.DatePicker.Selector"/>
- <style name="TextAppearance.DeviceDefault.Light.DatePicker.Selector" parent="TextAppearance.Material.Light.DatePicker.Selector"/>
-
- <style name="TextAppearance.DeviceDefault.DatePicker.Selector.MonthLabel" parent="TextAppearance.Material.DatePicker.Selector.MonthLabel"/>
- <style name="TextAppearance.DeviceDefault.Light.DatePicker.Selector.MonthLabel" parent="TextAppearance.Material.Light.DatePicker.Selector.MonthLabel"/>
-
- <style name="TextAppearance.DeviceDefault.DatePicker.Selector.DayOfMonthLabel" parent="TextAppearance.Material.DatePicker.Selector.DayOfMonthLabel"/>
- <style name="TextAppearance.DeviceDefault.Light.DatePicker.Selector.DayOfMonthLabel" parent="TextAppearance.Material.Light.DatePicker.Selector.DayOfMonthLabel"/>
-
- <style name="TextAppearance.DeviceDefault.DatePicker.Selector.YearLabel" parent="TextAppearance.Material.DatePicker.Selector.YearLabel"/>
- <style name="TextAppearance.DeviceDefault.Light.DatePicker.Selector.YearLabel" parent="TextAppearance.Material.Light.DatePicker.Selector.YearLabel"/>
-
- <style name="Theme.DeviceDefault.Dialog.DatePicker" parent="Theme.Material.Dialog.DatePicker"/>
- <style name="Theme.DeviceDefault.Light.Dialog.DatePicker" parent="Theme.Material.Light.Dialog.DatePicker"/>
-
</resources>
diff --git a/core/res/res/values/styles_holo.xml b/core/res/res/values/styles_holo.xml
index bf5fd29..d79e46d 100644
--- a/core/res/res/values/styles_holo.xml
+++ b/core/res/res/values/styles_holo.xml
@@ -473,24 +473,28 @@ please see styles_device_defaults.xml.
<item name="numbersTextColor">@color/timepicker_default_text_color_holo_dark</item>
<item name="numbersBackgroundColor">@color/timepicker_default_background_holo_dark</item>
<item name="amPmTextColor">@color/timepicker_default_text_color_holo_dark</item>
- <item name="amPmUnselectedBackgroundColor">@color/timepicker_default_background_holo_dark</item>
+ <item name="amPmBackgroundColor">@color/timepicker_default_background_holo_dark</item>
<item name="amPmSelectedBackgroundColor">@color/holo_blue_light</item>
<item name="numbersSelectorColor">@color/holo_blue_light</item>
</style>
<style name="Widget.Holo.DatePicker" parent="Widget.DatePicker">
+ <item name="legacyMode">true</item>
<item name="legacyLayout">@layout/date_picker_legacy_holo</item>
<item name="internalLayout">@layout/date_picker_holo</item>
<item name="calendarViewShown">true</item>
- <item name="dateSelectorDayOfWeekBackgroundColor">?attr/datePickerHeaderDayOfWeekLabelBackgroundColor</item>
- <item name="dateSelectorDayOfWeekTextAppearance">?attr/datePickerHeaderDayOfWeekLabelTextAppearance</item>
- <item name="dateSelectorBackgroundColor">?attr/datePickerHeaderSelectorBackgroundColor</item>
- <item name="dateSelectorMonthTextAppearance">?attr/datePickerHeaderSelectorMonthLabelTextAppearance</item>
- <item name="dateSelectorDayOfMonthTextAppearance">?attr/datePickerHeaderSelectorDayOfMonthLabelTextAppearance</item>
- <item name="dateSelectorYearTextAppearance">?attr/datePickerHeaderSelectorYearLabelTextAppearance</item>
- <item name="dateSelectorYearListItemTextAppearance">?attr/datePickerHeaderListYearLabelTextAppearance</item>
- <item name="dateSelectorYearListSelectedCircleColor">?attr/datePickerHeaderListYearLabelCircleBackgroundColor</item>
+ <!-- New-style date picker attributes. -->
+ <item name="dayOfWeekBackgroundColor">@color/datepicker_default_header_dayofweek_background_color_holo_dark</item>
+ <item name="dayOfWeekTextAppearance">@style/TextAppearance.Holo.DatePicker.DayOfWeekLabel</item>
+ <item name="headerBackgroundColor">@color/datepicker_default_header_selector_background_holo_dark</item>
+ <item name="headerMonthTextAppearance">@style/TextAppearance.Holo.DatePicker.Selector.MonthLabel</item>
+ <item name="headerDayOfMonthTextAppearance">@style/TextAppearance.Holo.DatePicker.Selector.DayOfMonthLabel</item>
+ <item name="headerYearTextAppearance">@style/TextAppearance.Holo.DatePicker.Selector.YearLabel</item>
+ <item name="headerSelectedTextColor">@color/holo_blue_light</item>
+ <item name="yearListItemTextAppearance">@style/TextAppearance.Holo.DatePicker.List.YearLabel</item>
+ <item name="yearListSelectorColor">@color/datepicker_default_circle_background_color_holo_dark</item>
<item name="calendarTextColor">@color/date_picker_calendar_holo_dark</item>
+ <item name="calendarSelectedTextColor">@color/holo_blue_light</item>
</style>
<style name="Widget.Holo.ActivityChooserView" parent="Widget.ActivityChooserView" />
@@ -893,24 +897,28 @@ please see styles_device_defaults.xml.
<item name="numbersTextColor">@color/timepicker_default_text_color_holo_light</item>
<item name="numbersBackgroundColor">@color/timepicker_default_background_holo_light</item>
<item name="amPmTextColor">@color/timepicker_default_text_color_holo_light</item>
- <item name="amPmUnselectedBackgroundColor">@color/timepicker_default_background_holo_light</item>
+ <item name="amPmBackgroundColor">@color/timepicker_default_background_holo_light</item>
<item name="amPmSelectedBackgroundColor">@color/holo_blue_light</item>
<item name="numbersSelectorColor">@color/holo_blue_light</item>
</style>
<style name="Widget.Holo.Light.DatePicker" parent="Widget.DatePicker">
+ <item name="legacyMode">true</item>
<item name="legacyLayout">@layout/date_picker_legacy_holo</item>
<item name="internalLayout">@layout/date_picker_holo</item>
<item name="calendarViewShown">true</item>
- <item name="dateSelectorDayOfWeekBackgroundColor">?attr/datePickerHeaderDayOfWeekLabelBackgroundColor</item>
- <item name="dateSelectorDayOfWeekTextAppearance">?attr/datePickerHeaderDayOfWeekLabelTextAppearance</item>
- <item name="dateSelectorBackgroundColor">?attr/datePickerHeaderSelectorBackgroundColor</item>
- <item name="dateSelectorMonthTextAppearance">?attr/datePickerHeaderSelectorMonthLabelTextAppearance</item>
- <item name="dateSelectorDayOfMonthTextAppearance">?attr/datePickerHeaderSelectorDayOfMonthLabelTextAppearance</item>
- <item name="dateSelectorYearTextAppearance">?attr/datePickerHeaderSelectorYearLabelTextAppearance</item>
- <item name="dateSelectorYearListItemTextAppearance">?attr/datePickerHeaderListYearLabelTextAppearance</item>
- <item name="dateSelectorYearListSelectedCircleColor">?attr/datePickerHeaderListYearLabelCircleBackgroundColor</item>
+ <!-- New-style date picker attributes. -->
+ <item name="dayOfWeekBackgroundColor">@color/datepicker_default_header_dayofweek_background_color_holo_light</item>
+ <item name="dayOfWeekTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.DayOfWeekLabel</item>
+ <item name="headerMonthTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.Selector.MonthLabel</item>
+ <item name="headerDayOfMonthTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.Selector.DayOfMonthLabel</item>
+ <item name="headerYearTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.Selector.YearLabel</item>
+ <item name="headerBackgroundColor">@color/datepicker_default_header_selector_background_holo_light</item>
+ <item name="headerSelectedTextColor">@color/holo_blue_light</item>
+ <item name="yearListItemTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.List.YearLabel</item>
+ <item name="yearListSelectorColor">@color/datepicker_default_circle_background_color_holo_light</item>
<item name="calendarTextColor">@color/date_picker_calendar_holo_light</item>
+ <item name="calendarSelectedTextColor">@color/holo_blue_light</item>
</style>
<style name="Widget.Holo.Light.ActivityChooserView" parent="Widget.Holo.ActivityChooserView">
diff --git a/core/res/res/values/styles_leanback.xml b/core/res/res/values/styles_leanback.xml
index b0f5864..a899c4d 100644
--- a/core/res/res/values/styles_leanback.xml
+++ b/core/res/res/values/styles_leanback.xml
@@ -27,6 +27,10 @@
<item name="legacyLayout">@layout/time_picker_legacy_leanback</item>
</style>
+ <style name="Widget.Leanback.DatePicker" parent="Widget.Material.DatePicker">
+ <item name="legacyMode">true</item>
+ </style>
+
<style name="Widget.Leanback.NumberPicker" parent="Widget.Material.NumberPicker">
<item name="hideWheelUntilFocused">true</item>
</style>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index a8974c6..61dff1b 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -355,57 +355,30 @@ please see styles_device_defaults.xml.
<style name="TextAppearance.Material.DatePicker.DayOfWeekLabel" parent="TextAppearance.Material">
<item name="includeFontPadding">false</item>
- <item name="textColor">@color/black</item>
+ <item name="textColor">?attr/textColorPrimary</item>
<item name="textSize">@dimen/datepicker_header_text_size</item>
</style>
- <style name="TextAppearance.Material.DatePicker.Selector" parent="TextAppearance.Material">
+ <style name="TextAppearance.Material.DatePicker.MonthLabel" parent="TextAppearance.Material">
<item name="includeFontPadding">false</item>
- <item name="textColor">@color/date_picker_selector_material_dark</item>
- </style>
-
- <style name="TextAppearance.Material.DatePicker.Selector.MonthLabel" parent="TextAppearance.Material.DatePicker.Selector">
+ <item name="textColor">?attr/textColorPrimary</item> <!-- selected should be accent -->
<item name="textSize">@dimen/datepicker_selected_date_month_size</item>
</style>
- <style name="TextAppearance.Material.DatePicker.Selector.DayOfMonthLabel" parent="TextAppearance.Material.DatePicker.Selector">
- <item name="textSize">@dimen/datepicker_selected_date_day_size</item>
- </style>
-
- <style name="TextAppearance.Material.DatePicker.Selector.YearLabel" parent="TextAppearance.Material.DatePicker.Selector">
- <item name="textSize">@dimen/datepicker_selected_date_year_size</item>
- </style>
-
- <style name="TextAppearance.Material.DatePicker.List.YearLabel" parent="TextAppearance.Material">
- <item name="textColor">@color/date_picker_year_selector_material_dark</item>
- <item name="textSize">@dimen/datepicker_year_label_text_size</item>
- </style>
-
- <style name="TextAppearance.Material.Light.DatePicker.DayOfWeekLabel" parent="TextAppearance.Material">
- <item name="includeFontPadding">false</item>
- <item name="textColor">@color/white</item>
- <item name="textSize">@dimen/datepicker_header_text_size</item>
- </style>
-
- <style name="TextAppearance.Material.Light.DatePicker.Selector" parent="TextAppearance.Material">
+ <style name="TextAppearance.Material.DatePicker.DayOfMonthLabel" parent="TextAppearance.Material">
<item name="includeFontPadding">false</item>
- <item name="textColor">@color/date_picker_selector_material_light</item>
- </style>
-
- <style name="TextAppearance.Material.Light.DatePicker.Selector.MonthLabel" parent="TextAppearance.Material.Light.DatePicker.Selector">
- <item name="textSize">@dimen/datepicker_selected_date_month_size</item>
- </style>
-
- <style name="TextAppearance.Material.Light.DatePicker.Selector.DayOfMonthLabel" parent="TextAppearance.Material.Light.DatePicker.Selector">
+ <item name="textColor">?attr/textColorPrimary</item> <!-- selected should be accent -->
<item name="textSize">@dimen/datepicker_selected_date_day_size</item>
</style>
- <style name="TextAppearance.Material.Light.DatePicker.Selector.YearLabel" parent="TextAppearance.Material.Light.DatePicker.Selector">
+ <style name="TextAppearance.Material.DatePicker.YearLabel" parent="TextAppearance.Material">
+ <item name="includeFontPadding">false</item>
+ <item name="textColor">?attr/textColorPrimary</item> <!-- selected should be accent -->
<item name="textSize">@dimen/datepicker_selected_date_year_size</item>
</style>
- <style name="TextAppearance.Material.Light.DatePicker.List.YearLabel" parent="TextAppearance.Material">
- <item name="textColor">@color/date_picker_year_selector_material_light</item>
+ <style name="TextAppearance.Material.DatePicker.List.YearLabel" parent="TextAppearance.Material">
+ <item name="textColor">?attr/textColorSecondary</item> <!-- selected should be accent -->
<item name="textSize">@dimen/datepicker_year_label_text_size</item>
</style>
@@ -618,6 +591,8 @@ please see styles_device_defaults.xml.
<style name="Widget.Material.TimePicker" parent="Widget.TimePicker">
<item name="legacyMode">false</item>
+ <item name="legacyLayout">@layout/time_picker_legacy_holo</item>
+ <!-- Attributes for new-style TimePicker. -->
<item name="internalLayout">@layout/time_picker_holo</item>
<item name="headerTimeTextAppearance">@style/TextAppearance.Material.TimePicker.TimeLabel</item>
<item name="headerAmPmTextAppearance">@style/TextAppearance.Material.TimePicker.AmPmLabel</item>
@@ -626,24 +601,28 @@ please see styles_device_defaults.xml.
<item name="numbersTextColor">?attr/textColorSecondary</item>
<item name="numbersBackgroundColor">@color/transparent</item>
<item name="amPmTextColor">?attr/textColorSecondary</item>
- <item name="amPmUnselectedBackgroundColor">@color/transparent</item>
+ <item name="amPmBackgroundColor">@color/transparent</item>
<item name="amPmSelectedBackgroundColor">?attr/colorControlActivated</item>
<item name="numbersSelectorColor">?attr/colorControlActivated</item>
</style>
<style name="Widget.Material.DatePicker" parent="Widget.DatePicker">
+ <item name="legacyMode">false</item>
<item name="legacyLayout">@layout/date_picker_legacy_holo</item>
+ <!-- Attributes for new-style DatePicker. -->
<item name="internalLayout">@layout/date_picker_holo</item>
<item name="calendarViewShown">true</item>
- <item name="dateSelectorDayOfWeekBackgroundColor">?attr/datePickerHeaderDayOfWeekLabelBackgroundColor</item>
- <item name="dateSelectorDayOfWeekTextAppearance">?attr/datePickerHeaderDayOfWeekLabelTextAppearance</item>
- <item name="dateSelectorBackgroundColor">?attr/datePickerHeaderSelectorBackgroundColor</item>
- <item name="dateSelectorMonthTextAppearance">?attr/datePickerHeaderSelectorMonthLabelTextAppearance</item>
- <item name="dateSelectorDayOfMonthTextAppearance">?attr/datePickerHeaderSelectorDayOfMonthLabelTextAppearance</item>
- <item name="dateSelectorYearTextAppearance">?attr/datePickerHeaderSelectorYearLabelTextAppearance</item>
- <item name="dateSelectorYearListItemTextAppearance">?attr/datePickerHeaderListYearLabelTextAppearance</item>
- <item name="dateSelectorYearListSelectedCircleColor">?attr/datePickerHeaderListYearLabelCircleBackgroundColor</item>
- <item name="calendarTextColor">@color/date_picker_calendar_holo_dark</item>
+ <item name="dayOfWeekBackgroundColor">@color/transparent</item>
+ <item name="dayOfWeekTextAppearance">@style/TextAppearance.Material.DatePicker.DayOfWeekLabel</item>
+ <item name="headerMonthTextAppearance">@style/TextAppearance.Material.DatePicker.MonthLabel</item>
+ <item name="headerDayOfMonthTextAppearance">@style/TextAppearance.Material.DatePicker.DayOfMonthLabel</item>
+ <item name="headerYearTextAppearance">@style/TextAppearance.Material.DatePicker.YearLabel</item>
+ <item name="headerSelectedTextColor">?attr/colorControlActivated</item>
+ <item name="headerBackgroundColor">@color/transparent</item>
+ <item name="yearListItemTextAppearance">@style/TextAppearance.Material.DatePicker.List.YearLabel</item>
+ <item name="yearListSelectorColor">?attr/colorControlActivated</item>
+ <item name="calendarTextColor">?attr/textColorSecondary</item>
+ <item name="calendarSelectedTextColor">?attr/colorControlActivated</item>
</style>
<style name="Widget.Material.ActivityChooserView" parent="Widget.ActivityChooserView">
@@ -961,22 +940,7 @@ please see styles_device_defaults.xml.
<style name="Widget.Material.Light.NumberPicker" parent="Widget.Material.NumberPicker"/>
<style name="Widget.Material.Light.TimePicker" parent="Widget.Material.TimePicker" />
-
- <style name="Widget.Material.Light.DatePicker" parent="Widget.DatePicker">
- <item name="legacyLayout">@layout/date_picker_legacy_holo</item>
- <item name="internalLayout">@layout/date_picker_holo</item>
- <item name="calendarViewShown">true</item>
- <item name="dateSelectorDayOfWeekBackgroundColor">?attr/datePickerHeaderDayOfWeekLabelBackgroundColor</item>
- <item name="dateSelectorDayOfWeekTextAppearance">?attr/datePickerHeaderDayOfWeekLabelTextAppearance</item>
- <item name="dateSelectorBackgroundColor">?attr/datePickerHeaderSelectorBackgroundColor</item>
- <item name="dateSelectorMonthTextAppearance">?attr/datePickerHeaderSelectorMonthLabelTextAppearance</item>
- <item name="dateSelectorDayOfMonthTextAppearance">?attr/datePickerHeaderSelectorDayOfMonthLabelTextAppearance</item>
- <item name="dateSelectorYearTextAppearance">?attr/datePickerHeaderSelectorYearLabelTextAppearance</item>
- <item name="dateSelectorYearListItemTextAppearance">?attr/datePickerHeaderListYearLabelTextAppearance</item>
- <item name="dateSelectorYearListSelectedCircleColor">?attr/datePickerHeaderListYearLabelCircleBackgroundColor</item>
- <item name="calendarTextColor">@color/date_picker_calendar_holo_light</item>
- </style>
-
+ <style name="Widget.Material.Light.DatePicker" parent="Widget.Material.DatePicker" />
<style name="Widget.Material.Light.ActivityChooserView" parent="Widget.Material.ActivityChooserView" />
<style name="Widget.Material.Light.ImageWell" parent="Widget.Material.ImageWell"/>
<style name="Widget.Material.Light.ListView" parent="Widget.Material.ListView"/>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 37dc046..723da4c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1844,20 +1844,7 @@
<java-symbol type="dimen" name="subtitle_shadow_offset" />
<java-symbol type="dimen" name="subtitle_outline_width" />
- <!-- From the new TimePicker and DatePicker -->
- <java-symbol type="attr" name="timePickerDialogTheme" />
- <java-symbol type="attr" name="headerSelectedTextColor" />
- <java-symbol type="attr" name="numbersTextColor" />
- <java-symbol type="attr" name="numbersBackgroundColor" />
- <java-symbol type="attr" name="amPmTextColor" />
- <java-symbol type="attr" name="amPmUnselectedBackgroundColor" />
- <java-symbol type="attr" name="amPmSelectedBackgroundColor" />
- <java-symbol type="attr" name="numbersSelectorColor" />
<java-symbol type="attr" name="nestedScrollingEnabled" />
- <java-symbol type="attr" name="datePickerDialogTheme" />
- <java-symbol type="attr" name="datePickerHeaderSelectorBackgroundColor" />
- <java-symbol type="attr" name="datePickerHeaderListYearLabelCircleBackgroundColor" />
- <java-symbol type="attr" name="calendarTextColor" />
<java-symbol type="style" name="TextAppearance.Holo.TimePicker.TimeLabel" />
@@ -1941,7 +1928,6 @@
<java-symbol type="array" name="config_calendarDateVibePattern" />
<!-- From various Material changes -->
- <java-symbol type="attr" name="toolbarStyle" />
<java-symbol type="attr" name="titleTextAppearance" />
<java-symbol type="attr" name="subtitleTextAppearance" />
<java-symbol type="attr" name="windowActionBarFullscreenDecorLayout" />
@@ -1975,6 +1961,7 @@
<java-symbol type="attr" name="lightRadius" />
<java-symbol type="attr" name="ambientShadowAlpha" />
<java-symbol type="attr" name="spotShadowAlpha" />
-
<java-symbol type="array" name="config_cdma_home_system" />
+ <java-symbol type="attr" name="headerSelectedTextColor" />
+ <java-symbol type="attr" name="amPmSelectedBackgroundColor" />
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index aea72c1..b36cdb9 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -396,39 +396,15 @@ please see themes_device_defaults.xml.
<item name="timePickerStyle">@style/Widget.TimePicker</item>
<!-- TimePicker dialog theme -->
- <item name="timePickerDialogTheme">@style/Theme.Dialog.TimePicker</item>
+ <item name="timePickerDialogTheme">?attr/alertDialogTheme</item>
<!-- DatePicker style -->
<item name="datePickerStyle">@style/Widget.DatePicker</item>
- <!-- DatePicker Header day of week label background color -->
- <item name="datePickerHeaderDayOfWeekLabelBackgroundColor">@android:color/darker_gray</item>
-
- <!-- DatePicker Header day of week label text appearance -->
- <item name="datePickerHeaderDayOfWeekLabelTextAppearance">@style/TextAppearance.DatePicker.DayOfWeekLabel</item>
-
- <!-- DatePicker Header selector background color -->
- <item name="datePickerHeaderSelectorBackgroundColor">@android:color/darker_gray</item>
-
- <!-- DatePicker Header selector month label text appearance -->
- <item name="datePickerHeaderSelectorMonthLabelTextAppearance">@style/TextAppearance.DatePicker.Selector.MonthLabel</item>
-
- <!-- DatePicker Header selector day of month label text appearance -->
- <item name="datePickerHeaderSelectorDayOfMonthLabelTextAppearance">@style/TextAppearance.DatePicker.Selector.DayOfMonthLabel</item>
-
- <!-- DatePicker Header selector year label text appearance -->
- <item name="datePickerHeaderSelectorYearLabelTextAppearance">@style/TextAppearance.DatePicker.Selector.YearLabel</item>
-
- <!-- DatePicker list year label text appearance -->
- <item name="datePickerHeaderListYearLabelTextAppearance">@style/TextAppearance.DatePicker.List.YearLabel</item>
-
- <!-- DatePicker list year label circle background color -->
- <item name="datePickerHeaderListYearLabelCircleBackgroundColor">@android:color/darker_gray</item>
-
<!-- DatePicker dialog theme -->
- <item name="datePickerDialogTheme">@android:style/Theme.Dialog.DatePicker</item>
+ <item name="datePickerDialogTheme">?attr/alertDialogTheme</item>
- <item name="fastScrollThumbDrawable">@android:drawable/scrollbar_handle_accelerated_anim2</item>
+ <item name="fastScrollThumbDrawable">@drawable/scrollbar_handle_accelerated_anim2</item>
<item name="fastScrollTrackDrawable">@null</item>
<item name="fastScrollPreviewBackgroundRight">@drawable/menu_submenu_background</item>
<item name="fastScrollPreviewBackgroundLeft">@drawable/menu_submenu_background</item>
@@ -744,22 +720,6 @@ please see themes_device_defaults.xml.
<item name="textAppearanceListItemSecondary">@style/TextAppearance.Small.Inverse</item>
</style>
- <!-- Default heme for the TimePicker dialog windows, which is used by the
- {@link android.app.TimePickerDialog} class. -->
- <style name="Theme.Dialog.TimePicker">
- <item name="windowBackground">@color/transparent</item>
- <item name="windowTitleStyle">@style/DialogWindowTitle</item>
- <item name="windowContentOverlay">@null</item>
- </style>
-
- <!-- Default heme for the DatePicker dialog windows, which is used by the
- {@link android.app.DatePickerDialog} class. -->
- <style name="Theme.Dialog.DatePicker">
- <item name="windowBackground">@android:color/transparent</item>
- <item name="windowTitleStyle">@android:style/DialogWindowTitle</item>
- <item name="windowContentOverlay">@null</item>
- </style>
-
<!-- Default dark theme for panel windows (on API level 10 and lower). This removes all
extraneous window decorations, so you basically have an empty rectangle in which
to place your content. It makes the window floating, with a transparent
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 43381d6..36d7116 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -195,27 +195,9 @@ easier.
<!-- TimePicker style -->
<item name="timePickerStyle">@style/Widget.DeviceDefault.TimePicker</item>
- <!-- TimePicker dialog theme -->
- <item name="timePickerDialogTheme">@style/Theme.DeviceDefault.Dialog.TimePicker</item>
-
<!-- DatePicker style -->
<item name="datePickerStyle">@style/Widget.DeviceDefault.DatePicker</item>
- <!-- The DatePicker Header day of week label text appearance -->
- <item name="datePickerHeaderDayOfWeekLabelTextAppearance">@style/TextAppearance.DeviceDefault.DatePicker.DayOfWeekLabel</item>
-
- <!-- The DatePicker Header selector month label text appearance -->
- <item name="datePickerHeaderSelectorMonthLabelTextAppearance">@style/TextAppearance.DeviceDefault.DatePicker.Selector.MonthLabel</item>
-
- <!-- The DatePicker Header selector day of month label text appearance -->
- <item name="datePickerHeaderSelectorDayOfMonthLabelTextAppearance">@style/TextAppearance.DeviceDefault.DatePicker.Selector.DayOfMonthLabel</item>
-
- <!-- The DatePicker Header selector year label text appearance -->
- <item name="datePickerHeaderSelectorYearLabelTextAppearance">@style/TextAppearance.DeviceDefault.DatePicker.Selector.YearLabel</item>
-
- <!-- DatePicker dialog theme -->
- <item name="datePickerDialogTheme">@android:style/Theme.DeviceDefault.Dialog.DatePicker</item>
-
<item name="mediaRouteButtonStyle">@style/Widget.DeviceDefault.MediaRouteButton</item>
</style>
@@ -291,8 +273,6 @@ easier.
<!-- DeviceDefault theme for a presentation window on a secondary display. -->
<style name="Theme.DeviceDefault.Dialog.Presentation" parent="Theme.Material.Dialog.Presentation" />
- <style name="Theme.DeviceDefault.Dialog.TimePicker" parent="Theme.Material.Dialog.TimePicker"/>
-
<!-- DeviceDefault theme for panel windows. This removes all extraneous window
decorations, so you basically have an empty rectangle in which to place your content. It makes
the window floating, with a transparent background, and turns off dimming behind the window. -->
@@ -464,27 +444,9 @@ easier.
<!-- TimePicker style -->
<item name="timePickerStyle">@style/Widget.DeviceDefault.Light.TimePicker</item>
- <!-- TimePicker dialog theme -->
- <item name="timePickerDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.TimePicker</item>
-
<!-- DatePicker style -->
<item name="datePickerStyle">@style/Widget.DeviceDefault.Light.DatePicker</item>
- <!-- The DatePicker Header day of week label text appearance -->
- <item name="datePickerHeaderDayOfWeekLabelTextAppearance">@style/TextAppearance.DeviceDefault.Light.DatePicker.DayOfWeekLabel</item>
-
- <!-- The DatePicker Header selector month label text appearance -->
- <item name="datePickerHeaderSelectorMonthLabelTextAppearance">@style/TextAppearance.DeviceDefault.Light.DatePicker.Selector.MonthLabel</item>
-
- <!-- The DatePicker Header selector day of month label text appearance -->
- <item name="datePickerHeaderSelectorDayOfMonthLabelTextAppearance">@style/TextAppearance.DeviceDefault.Light.DatePicker.Selector.DayOfMonthLabel</item>
-
- <!-- The DatePicker Header selector year label text appearance -->
- <item name="datePickerHeaderSelectorYearLabelTextAppearance">@style/TextAppearance.DeviceDefault.Light.DatePicker.Selector.YearLabel</item>
-
- <!-- DatePicker dialog theme -->
- <item name="datePickerDialogTheme">@android:style/Theme.DeviceDefault.Light.Dialog.DatePicker</item>
-
<item name="mediaRouteButtonStyle">@style/Widget.DeviceDefault.Light.MediaRouteButton</item>
</style>
@@ -564,8 +526,6 @@ easier.
<!-- DeviceDefault light theme for a presentation window on a secondary display. -->
<style name="Theme.DeviceDefault.Light.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation" />
- <style name="Theme.DeviceDefault.Light.Dialog.TimePicker" parent="Theme.Material.Light.Dialog.TimePicker"/>
-
<!-- DeviceDefault light theme for panel windows. This removes all extraneous window
decorations, so you basically have an empty rectangle in which to place your content. It makes
the window floating, with a transparent background, and turns off dimming behind the window. -->
diff --git a/core/res/res/values/themes_holo.xml b/core/res/res/values/themes_holo.xml
index f6c6b4c..14853b8 100644
--- a/core/res/res/values/themes_holo.xml
+++ b/core/res/res/values/themes_holo.xml
@@ -375,37 +375,13 @@ please see themes_device_defaults.xml.
<item name="timePickerStyle">@style/Widget.Holo.TimePicker</item>
<!-- TimePicker dialog theme -->
- <item name="timePickerDialogTheme">@style/Theme.Holo.Dialog.TimePicker</item>
+ <item name="timePickerDialogTheme">?attr/alertDialogTheme</item>
<!-- DatePicker style -->
<item name="datePickerStyle">@style/Widget.Holo.DatePicker</item>
- <!-- DatePicker Header day of week label background color -->
- <item name="datePickerHeaderDayOfWeekLabelBackgroundColor">@android:color/datepicker_default_header_dayofweek_background_color_holo_dark</item>
-
- <!-- DatePicker Header day of week label text appearance -->
- <item name="datePickerHeaderDayOfWeekLabelTextAppearance">@style/TextAppearance.Holo.DatePicker.DayOfWeekLabel</item>
-
- <!-- DatePicker Header selector background color -->
- <item name="datePickerHeaderSelectorBackgroundColor">@android:color/datepicker_default_header_selector_background_holo_dark</item>
-
- <!-- DatePicker Header selector month label text appearance -->
- <item name="datePickerHeaderSelectorMonthLabelTextAppearance">@style/TextAppearance.Holo.DatePicker.Selector.MonthLabel</item>
-
- <!-- DatePicker Header selector day of month label text appearance -->
- <item name="datePickerHeaderSelectorDayOfMonthLabelTextAppearance">@style/TextAppearance.Holo.DatePicker.Selector.DayOfMonthLabel</item>
-
- <!-- DatePicker Header selector year label text appearance -->
- <item name="datePickerHeaderSelectorYearLabelTextAppearance">@style/TextAppearance.Holo.DatePicker.Selector.YearLabel</item>
-
- <!-- DatePicker list year label text appearance -->
- <item name="datePickerHeaderListYearLabelTextAppearance">@style/TextAppearance.Holo.DatePicker.List.YearLabel</item>
-
- <!-- DatePicker list year label circle background color -->
- <item name="datePickerHeaderListYearLabelCircleBackgroundColor">@android:color/datepicker_default_circle_background_color_holo_dark</item>
-
<!-- DatePicker dialog theme -->
- <item name="datePickerDialogTheme">@android:style/Theme.Holo.Dialog.DatePicker</item>
+ <item name="datePickerDialogTheme">?attr/alertDialogTheme</item>
<item name="fastScrollThumbDrawable">@drawable/fastscroll_thumb_holo</item>
<item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_dark</item>
@@ -732,37 +708,13 @@ please see themes_device_defaults.xml.
<item name="timePickerStyle">@style/Widget.Holo.Light.TimePicker</item>
<!-- TimePicker dialog theme -->
- <item name="timePickerDialogTheme">@style/Theme.Holo.Light.Dialog.TimePicker</item>
+ <item name="timePickerDialogTheme">?attr/alertDialogTheme</item>
<!-- DatePicker style -->
<item name="datePickerStyle">@style/Widget.Holo.Light.DatePicker</item>
- <!-- DatePicker Header day of week label background color -->
- <item name="datePickerHeaderDayOfWeekLabelBackgroundColor">@android:color/datepicker_default_header_dayofweek_background_color_holo_light</item>
-
- <!-- DatePicker Header day of week label text appearance -->
- <item name="datePickerHeaderDayOfWeekLabelTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.DayOfWeekLabel</item>
-
- <!-- DatePicker Header selector background color -->
- <item name="datePickerHeaderSelectorBackgroundColor">@android:color/datepicker_default_header_selector_background_holo_light</item>
-
- <!-- DatePicker Header selector month label text appearance -->
- <item name="datePickerHeaderSelectorMonthLabelTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.Selector.MonthLabel</item>
-
- <!-- DatePicker Header selector day of month label text appearance -->
- <item name="datePickerHeaderSelectorDayOfMonthLabelTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.Selector.DayOfMonthLabel</item>
-
- <!-- DatePicker Header selector year label text appearance -->
- <item name="datePickerHeaderSelectorYearLabelTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.Selector.YearLabel</item>
-
- <!-- DatePicker list year label text appearance -->
- <item name="datePickerHeaderListYearLabelTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.List.YearLabel</item>
-
- <!-- DatePicker list year label circle background color -->
- <item name="datePickerHeaderListYearLabelCircleBackgroundColor">@android:color/datepicker_default_circle_background_color_holo_light</item>
-
<!-- DatePicker dialog theme -->
- <item name="datePickerDialogTheme">@android:style/Theme.Holo.Light.Dialog.DatePicker</item>
+ <item name="datePickerDialogTheme">?attr/alertDialogTheme</item>
<item name="fastScrollThumbDrawable">@drawable/fastscroll_thumb_holo</item>
<item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_light</item>
@@ -976,18 +928,6 @@ please see themes_device_defaults.xml.
AlertDialog theme. -->
<style name="Theme.Holo.Dialog.Alert" parent="Theme.Holo.Dialog.BaseAlert" />
- <!-- Holo theme for the TimePicker dialog windows, which is used by the
- {@link android.app.TimePickerDialog} class. -->
- <style name="Theme.Holo.Dialog.TimePicker" parent="Theme.Holo.Dialog.Alert" />
-
- <!-- Holo theme for the DatePicker dialog windows, which is used by the
- {@link android.app.DatePickerDialog} class. -->
- <style name="Theme.Holo.Dialog.DatePicker">
- <item name="windowBackground">@color/transparent</item>
- <item name="windowTitleStyle">@style/DialogWindowTitle.Holo</item>
- <item name="windowContentOverlay">@null</item>
- </style>
-
<!-- Theme for a window that will be displayed either full-screen on
smaller screens (small, normal) or as a dialog on larger screens
(large, xlarge). -->
@@ -1099,18 +1039,6 @@ please see themes_device_defaults.xml.
AlertDialog theme. -->
<style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Holo.Light.Dialog.BaseAlert" />
- <!-- Holo Light theme for the TimePicker dialog windows, which is used by the
- {@link android.app.TimePickerDialog} class. -->
- <style name="Theme.Holo.Light.Dialog.TimePicker" parent="Theme.Holo.Light.Dialog.Alert" />
-
- <!-- Holo Light theme for the DatePicker dialog windows, which is used by the
- {@link android.app.DatePickerDialog} class. -->
- <style name="Theme.Holo.Light.Dialog.DatePicker">
- <item name="windowBackground">@android:color/transparent</item>
- <item name="windowTitleStyle">@android:style/DialogWindowTitle.Holo.Light</item>
- <item name="windowContentOverlay">@null</item>
- </style>
-
<!-- Theme for a presentation window on a secondary display. -->
<style name="Theme.Holo.Light.Dialog.Presentation" parent="Theme.Holo.Light.NoActionBar.Fullscreen" />
diff --git a/core/res/res/values/themes_leanback.xml b/core/res/res/values/themes_leanback.xml
index 534e323..321b827 100644
--- a/core/res/res/values/themes_leanback.xml
+++ b/core/res/res/values/themes_leanback.xml
@@ -19,27 +19,11 @@
<item name="textColorPrimary">@color/primary_text_leanback_dark</item>
<item name="textColorSecondary">@color/secondary_text_leanback_dark</item>
<item name="alertDialogStyle">@style/AlertDialog.Leanback</item>
- <item name="numberPickerStyle">@style/Widget.Leanback.NumberPicker</item>
- </style>
-
- <style name="Theme.Leanback.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.BaseAlert">
- <item name="colorBackground">@color/background_leanback_light</item>
- <item name="textColorPrimary">@color/primary_text_leanback_light</item>
- <item name="textColorSecondary">@color/secondary_text_leanback_light</item>
- <item name="alertDialogStyle">@style/AlertDialog.Leanback.Light</item>
- <item name="numberPickerStyle">@style/Widget.Leanback.NumberPicker</item>
- </style>
-
- <style name="Theme.Leanback.Dialog.TimePicker" parent="Theme.Material.Dialog.BaseTimePicker">
- <item name="colorBackground">@color/background_leanback_dark</item>
- <item name="textColorPrimary">@color/primary_text_leanback_dark</item>
- <item name="textColorSecondary">@color/secondary_text_leanback_dark</item>
- <item name="alertDialogStyle">@style/AlertDialog.Leanback</item>
<item name="timePickerStyle">@style/Widget.Leanback.TimePicker</item>
<item name="numberPickerStyle">@style/Widget.Leanback.NumberPicker</item>
</style>
- <style name="Theme.Leanback.Light.Dialog.TimePicker" parent="Theme.Material.Light.Dialog.BaseTimePicker">
+ <style name="Theme.Leanback.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.BaseAlert">
<item name="colorBackground">@color/background_leanback_light</item>
<item name="textColorPrimary">@color/primary_text_leanback_light</item>
<item name="textColorSecondary">@color/secondary_text_leanback_light</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index f2233e0..42ebb82 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -354,37 +354,13 @@ please see themes_device_defaults.xml.
<item name="timePickerStyle">@style/Widget.Material.TimePicker</item>
<!-- TimePicker dialog theme -->
- <item name="timePickerDialogTheme">@style/Theme.Material.Dialog.TimePicker</item>
+ <item name="timePickerDialogTheme">?attr/alertDialogTheme</item>
<!-- DatePicker style -->
- <item name="datePickerStyle">@style/Widget.Material.DatePicker</item>
-
- <!-- DatePicker Header day of week label background color -->
- <item name="datePickerHeaderDayOfWeekLabelBackgroundColor">@android:color/datepicker_default_header_dayofweek_background_color_material_dark</item>
-
- <!-- DatePicker Header day of week label text appearance -->
- <item name="datePickerHeaderDayOfWeekLabelTextAppearance">@style/TextAppearance.Material.DatePicker.DayOfWeekLabel</item>
-
- <!-- DatePicker Header selector background color -->
- <item name="datePickerHeaderSelectorBackgroundColor">@android:color/datepicker_default_header_selector_background_material_dark</item>
-
- <!-- DatePicker Header selector month label text appearance -->
- <item name="datePickerHeaderSelectorMonthLabelTextAppearance">@style/TextAppearance.Material.DatePicker.Selector.MonthLabel</item>
-
- <!-- DatePicker Header selector day of month label text appearance -->
- <item name="datePickerHeaderSelectorDayOfMonthLabelTextAppearance">@style/TextAppearance.Material.DatePicker.Selector.DayOfMonthLabel</item>
-
- <!-- DatePicker Header selector year label text appearance -->
- <item name="datePickerHeaderSelectorYearLabelTextAppearance">@style/TextAppearance.Material.DatePicker.Selector.YearLabel</item>
-
- <!-- DatePicker list year label text appearance -->
- <item name="datePickerHeaderListYearLabelTextAppearance">@style/TextAppearance.Material.DatePicker.List.YearLabel</item>
-
- <!-- DatePicker list year label circle background color -->
- <item name="datePickerHeaderListYearLabelCircleBackgroundColor">@android:color/datepicker_default_circle_background_color_material_dark</item>
+ <item name="datePickerStyle">?attr/alertDialogTheme</item>
<!-- DatePicker dialog theme -->
- <item name="datePickerDialogTheme">@android:style/Theme.Material.Dialog.DatePicker</item>
+ <item name="datePickerDialogTheme">@style/Theme.Material.Dialog.Alert</item>
<!-- TODO: This belongs in a FastScroll style -->
<item name="fastScrollThumbDrawable">@drawable/fastscroll_thumb_material</item>
@@ -721,37 +697,13 @@ please see themes_device_defaults.xml.
<item name="timePickerStyle">@style/Widget.Material.Light.TimePicker</item>
<!-- TimePicker dialog theme -->
- <item name="timePickerDialogTheme">@style/Theme.Material.Light.Dialog.TimePicker</item>
+ <item name="timePickerDialogTheme">?attr/alertDialogTheme</item>
<!-- DatePicker style -->
<item name="datePickerStyle">@style/Widget.Material.Light.DatePicker</item>
- <!-- DatePicker Header day of week label background color -->
- <item name="datePickerHeaderDayOfWeekLabelBackgroundColor">@android:color/datepicker_default_header_dayofweek_background_color_material_light</item>
-
- <!-- DatePicker Header day of week label text appearance -->
- <item name="datePickerHeaderDayOfWeekLabelTextAppearance">@style/TextAppearance.Material.Light.DatePicker.DayOfWeekLabel</item>
-
- <!-- DatePicker Header selector background color -->
- <item name="datePickerHeaderSelectorBackgroundColor">@android:color/datepicker_default_header_selector_background_material_light</item>
-
- <!-- DatePicker Header selector month label text appearance -->
- <item name="datePickerHeaderSelectorMonthLabelTextAppearance">@style/TextAppearance.Material.Light.DatePicker.Selector.MonthLabel</item>
-
- <!-- DatePicker Header selector day of month label text appearance -->
- <item name="datePickerHeaderSelectorDayOfMonthLabelTextAppearance">@style/TextAppearance.Material.Light.DatePicker.Selector.DayOfMonthLabel</item>
-
- <!-- DatePicker Header selector year label text appearance -->
- <item name="datePickerHeaderSelectorYearLabelTextAppearance">@style/TextAppearance.Material.Light.DatePicker.Selector.YearLabel</item>
-
- <!-- DatePicker list year label text appearance -->
- <item name="datePickerHeaderListYearLabelTextAppearance">@style/TextAppearance.Material.Light.DatePicker.List.YearLabel</item>
-
- <!-- DatePicker list year label circle background color -->
- <item name="datePickerHeaderListYearLabelCircleBackgroundColor">@android:color/datepicker_default_circle_background_color_material_light</item>
-
<!-- DatePicker dialog theme -->
- <item name="datePickerDialogTheme">@android:style/Theme.Material.Light.Dialog.DatePicker</item>
+ <item name="datePickerDialogTheme">?attr/alertDialogTheme</item>
<item name="fastScrollThumbDrawable">@drawable/fastscroll_thumb_material</item>
<item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_light</item>
@@ -1125,7 +1077,6 @@ please see themes_device_defaults.xml.
</style>
<style name="Theme.Material.Dialog.BaseAlert">
- <item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
<item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
<item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
</style>
@@ -1137,23 +1088,6 @@ please see themes_device_defaults.xml.
AlertDialog theme. -->
<style name="Theme.Material.Dialog.Alert" parent="Theme.Material.Dialog.BaseAlert"/>
- <!-- Base theme used to prevent circular references in Leanback overrides. -->
- <style name="Theme.Material.Dialog.BaseTimePicker" />
-
- <!-- Material theme for the TimePicker dialog windows, which is used by the
- {@link android.app.TimePickerDialog} class. -->
- <style name="Theme.Material.Dialog.TimePicker" parent="Theme.Material.Dialog.BaseTimePicker"/>
-
- <style name="Theme.Material.Dialog.BaseDatePicker">
- <item name="windowBackground">@color/transparent</item>
- <item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
- <item name="windowContentOverlay">@null</item>
- </style>
-
- <!-- Material theme for the DatePicker dialog windows, which is used by the
- {@link android.app.DatePickerDialog} class. -->
- <style name="Theme.Material.Dialog.DatePicker" parent="Theme.Material.Dialog.BaseDatePicker"/>
-
<!-- Theme for a window that will be displayed either full-screen on
smaller screens (small, normal) or as a dialog on larger screens
(large, xlarge). -->
@@ -1250,7 +1184,6 @@ please see themes_device_defaults.xml.
<style name="Theme.Material.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.Light.NoActionBar" />
<style name="Theme.Material.Light.Dialog.BaseAlert">
- <item name="windowTitleStyle">@style/DialogWindowTitle.Material.Light</item>
<item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
<item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
</style>
@@ -1269,11 +1202,7 @@ please see themes_device_defaults.xml.
{@link android.app.TimePickerDialog} class. -->
<style name="Theme.Material.Light.Dialog.TimePicker" parent="Theme.Material.Light.Dialog.BaseTimePicker" />
- <style name="Theme.Material.Light.Dialog.BaseDatePicker">
- <item name="windowBackground">@color/transparent</item>
- <item name="windowTitleStyle">@style/DialogWindowTitle.Material.Light</item>
- <item name="windowContentOverlay">@null</item>
- </style>
+ <style name="Theme.Material.Light.Dialog.BaseDatePicker" />
<!-- Material Light theme for the DatePicker dialog windows, which is used by the
{@link android.app.DatePickerDialog} class. -->
diff --git a/docs/html/images/tools/as-allocstart.png b/docs/html/images/tools/as-allocstart.png
new file mode 100644
index 0000000..b9c770a
--- /dev/null
+++ b/docs/html/images/tools/as-allocstart.png
Binary files differ
diff --git a/docs/html/images/tools/as-allocstop.png b/docs/html/images/tools/as-allocstop.png
new file mode 100644
index 0000000..8271161
--- /dev/null
+++ b/docs/html/images/tools/as-allocstop.png
Binary files differ
diff --git a/docs/html/images/tools/as-alloctrack.png b/docs/html/images/tools/as-alloctrack.png
new file mode 100644
index 0000000..4280f02
--- /dev/null
+++ b/docs/html/images/tools/as-alloctrack.png
Binary files differ
diff --git a/docs/html/sdk/installing/studio-debug.jd b/docs/html/sdk/installing/studio-debug.jd
index 7e2efe3..2e3e137 100644
--- a/docs/html/sdk/installing/studio-debug.jd
+++ b/docs/html/sdk/installing/studio-debug.jd
@@ -19,6 +19,7 @@ page.title=Debugging with Android Studio
<li><a href="#breakPointsDebug">Debug your app with breakpoints</a></li>
</ol>
</li>
+ <li><a href="#allocTracker">Track Object Allocation</a></li>
<li><a href="#deviceMonitor">Analyze Runtime Metrics to Optimize your App</a></li>
<li><a href="#screenCap">Capture Screenshots and Videos</a></li>
</ol>
@@ -281,6 +282,47 @@ step:</p>
<p class="img-caption"><strong>Figure 7.</strong> The Variables view in the Debug tool window.</p>
+<h2 id="allocTracker">Track Object Allocation</h2>
+
+<p>Android Studio lets you track objects that are being allocated on the Java heap and see which
+classes and threads are allocating these objects. This allows you to see the list of objects
+allocated during a period of interest. This information is valuable for assessing memory usage
+that can affect application performance.</p>
+
+<p>To track memory allocation of objects:</p>
+
+<ol>
+<li>Start your app as described in <a href="#runDebug">Run Your App in Debug Mode</a>.</li>
+<li>Click <strong>Android</strong> <img src="{@docRoot}images/tools/as-android.png" alt=""
+style="vertical-align:bottom;margin:0;height:20px"/> to open the <em>Android DDMS</em>
+tool window.</li>
+<li>On the <em>Android DDMS</em> tool window, select the <strong>Devices | logcat tab</strong>.</li>
+<li>Select your device from the dropdown list.</li>
+<li>Select your app by its package name from the list of running apps.</li>
+<li>Click <strong>Start Allocation Tracking</strong>
+<img src="{@docRoot}images/tools/as-allocstart.png" alt=""
+style="vertical-align:bottom;margin:0;height:20px"/></li>
+<li>Interact with your app on the device.</li>
+<li>Click <strong>Stop Allocation Tracking</strong>
+<img src="{@docRoot}images/tools/as-allocstop.png" alt=""
+style="vertical-align:bottom;margin:0;height:20px"/></li>
+</ol>
+
+<p>Android Studio shows the objects that the system allocated with the following information:</p>
+
+<ul>
+<li>Allocation order</li>
+<li>Allocated class</li>
+<li>Allocation size</li>
+<li>Thread ID</li>
+<li>Allocation method, class, and line number</li>
+<li>Stack trace at the point of allocation</li>
+</ul>
+
+<img src="{@docRoot}images/tools/as-alloctrack.png" alt="" width="750" height="252" />
+<p class="img-caption"><strong>Figure 8.</strong> Object allocation tracking in Android Studio.</p>
+
+
<h2 id="deviceMonitor">Analyze Runtime Metrics to Optimize your App</h2>
<p>Even if your application does not generate runtime errors, this does not mean it is free of
diff --git a/docs/html/training/wearables/apps/creating.jd b/docs/html/training/wearables/apps/creating.jd
index 09a90c8..7252ada 100644
--- a/docs/html/training/wearables/apps/creating.jd
+++ b/docs/html/training/wearables/apps/creating.jd
@@ -112,7 +112,7 @@ Project</a>. As you follow the wizard, enter the following information:</p>
name.</li>
<li>In the <b>Form Factors</b> window:
<ul>
- <li>Select <b>Phone and Tablet</b> and select <b>API 8: Android 2.2 (Froyo)</b>
+ <li>Select <b>Phone and Tablet</b> and select <b>API 9: Android 2.3 (Gingerbread)</b>
under <b>Minimum SDK</b>.</li>
<li>Select <b>Wear</b> and select <b>API 20: Android 4.4 (KitKat Wear)</b>
under <b>Minimum SDK</b>.</li>
diff --git a/docs/html/training/wearables/apps/packaging.jd b/docs/html/training/wearables/apps/packaging.jd
index 480f712..b538d6e 100644
--- a/docs/html/training/wearables/apps/packaging.jd
+++ b/docs/html/training/wearables/apps/packaging.jd
@@ -62,7 +62,7 @@ android {
release {
...
signingConfig signingConfigs.release
- }d
+ }
}
...
}
@@ -142,4 +142,4 @@ logs the following error: "this file cannot be opened as a file descriptor; it i
</p>
<p>Android Studio doesn't compress your APK by default, but if you are using another build process,
-ensure that you don't doubly compress the wearable app.</p> \ No newline at end of file
+ensure that you don't doubly compress the wearable app.</p>
diff --git a/docs/html/training/wearables/apps/voice.jd b/docs/html/training/wearables/apps/voice.jd
index 639d90a..4aa8031 100644
--- a/docs/html/training/wearables/apps/voice.jd
+++ b/docs/html/training/wearables/apps/voice.jd
@@ -119,7 +119,7 @@ named <code>MyNoteActivity</code>:
<td>
<dl>
<dt>Action</dt>
- <dd><code>android.provider.AlarmClock.ACTION_SET_TIMER</code></dd>
+ <dd><code>android.intent.action.SET_TIMER</code></dd>
<dt>Extras</dt>
<dd><code>android.provider.AlarmClock.EXTRA_LENGTH</code> - an integer in the range of
1 to 86400 (number of seconds in 24 hours) representing the length of the timer </dd>
@@ -244,7 +244,7 @@ from users and then process it, such as doing a search or sending it as a messag
In your app, you call {@link android.app.Activity#startActivityForResult startActivityForResult()} using
the {@link android.speech.RecognizerIntent#ACTION_RECOGNIZE_SPEECH} action. This starts the
- and then handle the result
+speech recognition activity, and you can then handle the result
in {@link android.app.Activity#onActivityResult onActivityResult()}.
<pre>
private static final int SPEECH_REQUEST_CODE = 0;
diff --git a/docs/html/training/wearables/data-layer/events.jd b/docs/html/training/wearables/data-layer/events.jd
index a37afe0..9e8acbc 100644
--- a/docs/html/training/wearables/data-layer/events.jd
+++ b/docs/html/training/wearables/data-layer/events.jd
@@ -102,12 +102,12 @@ so the handheld app doesn't listen for any data events from the wearable app.</p
<ul>
<li><a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)"><code>onDataChanged()</code></a>
- Called when data item objects are created, changed, or deleted. An event on one side of a connection
-triggers an this callback on both sides.</li>
+triggers this callback on both sides.</li>
<li><a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onMessageReceived(com.google.android.gms.wearable.MessageEvent)"><code>onMessageReceived()</code></a>
- A message sent from one side of a connection triggers this callback on the other side of the connection.</li>
<li><a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onMessageReceived(com.google.android.gms.wearable.MessageEvent)"><code>onPeerConnected()</code></a>
and <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onPeerDisconnected(com.google.android.gms.wearable.Node)"><code>onPeerDisconnected()</code></a> -
- Called when connection with the handheld or wearable is connected or disconnected.
+ Called when connection with the handheld or wearable is connected or disconnected.
Changes in connection state on one side of the connection triggers these callbacks on both sides of the connection.
</li>
</ul>
@@ -174,7 +174,7 @@ public class DataLayerListenerService extends WearableListenerService {
}
}
}
-</pre>
+</pre>
<p>Here's the corresponding intent filter in the Android manifest file:</p>
diff --git a/docs/html/training/wearables/data-layer/messages.jd b/docs/html/training/wearables/data-layer/messages.jd
index d0d5a0c..15e552d 100644
--- a/docs/html/training/wearables/data-layer/messages.jd
+++ b/docs/html/training/wearables/data-layer/messages.jd
@@ -95,5 +95,5 @@ public void onMessageReceived(MessageEvent messageEvent) {
<p>
This is just a snippet that requires more implementation details. Learn about
how to implement a full listener service or activity in
-<a href="#listening">Listening for Data Layer Events</a>.
+<a href="{@docRoot}training/wearables/data-layer/events.html">Listening for Data Layer Events</a>.
</p> \ No newline at end of file
diff --git a/docs/html/training/wearables/notifications/creating.jd b/docs/html/training/wearables/notifications/creating.jd
index a61fa07..d6ad34a 100644
--- a/docs/html/training/wearables/notifications/creating.jd
+++ b/docs/html/training/wearables/notifications/creating.jd
@@ -33,7 +33,15 @@ that use custom card layouts by creating a wearable app that runs on the wearabl
</div>
<h2 id="Import">Import the necessary classes</h2>
-<p>Before you begin, import the necessary classes from the support library:</p>
+
+<p>To import the necessary packages, add this line to your <code>build.gradle</code>file:</p>
+
+<pre>
+compile "com.android.support:support-v4:20.0.+"
+</pre>
+
+<p>Now that your project has access to the necessary packages, import the necessary classes from
+the support library:</p>
<pre style="clear:right">
import android.support.v4.app.NotificationCompat;
@@ -190,7 +198,7 @@ bigStyle.bigText(eventDescription);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_event)
- .setLargeIcon(BitmapFractory.decodeResource(
+ .setLargeIcon(BitmapFactory.decodeResource(
getResources(), R.drawable.notif_background))
.setContentTitle(eventTitle)
.setContentText(eventLocation)
@@ -292,4 +300,4 @@ boolean hintHideIcon = wearableExtender.getHintHideIcon();
<p>The {@link android.support.v4.app.NotificationCompat.WearableExtender} APIs allow you to add
additional pages to notifications, stack notifications, and more. Continue to the following lessons
to learn about these features.
-</p> \ No newline at end of file
+</p>
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 0c9c558..eb7291c 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -525,16 +525,6 @@ public class RippleDrawable extends LayerDrawable {
}
private void clearHotspots() {
- if (mRipple != null) {
- mRipple.cancel();
- mRipple = null;
- }
-
- if (mBackground != null) {
- mBackground.cancel();
- mBackground = null;
- }
-
final int count = mAnimatingRipplesCount;
final Ripple[] ripples = mAnimatingRipples;
for (int i = 0; i < count; i++) {
@@ -543,6 +533,21 @@ public class RippleDrawable extends LayerDrawable {
final Ripple ripple = ripples[i];
ripples[i] = null;
ripple.cancel();
+
+ // The active ripple may also be animating. Don't cancel it twice.
+ if (mRipple == ripple) {
+ mRipple = null;
+ }
+ }
+
+ if (mRipple != null) {
+ mRipple.cancel();
+ mRipple = null;
+ }
+
+ if (mBackground != null) {
+ mBackground.cancel();
+ mBackground = null;
}
mAnimatingRipplesCount = 0;
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 2889ea3..d765b25 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -504,19 +504,22 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
charSize = sizeof(char16_t);
}
- mStrings = (const void*)
- (((const uint8_t*)data)+mHeader->stringsStart);
- if (mHeader->stringsStart >= (mHeader->header.size-sizeof(uint16_t))) {
+ // There should be at least space for the smallest string
+ // (2 bytes length, null terminator).
+ if (mHeader->stringsStart >= (mSize - sizeof(uint16_t))) {
ALOGW("Bad string block: string pool starts at %d, after total size %d\n",
(int)mHeader->stringsStart, (int)mHeader->header.size);
return (mError=BAD_TYPE);
}
+
+ mStrings = (const void*)
+ (((const uint8_t*)data) + mHeader->stringsStart);
+
if (mHeader->styleCount == 0) {
- mStringPoolSize =
- (mHeader->header.size-mHeader->stringsStart)/charSize;
+ mStringPoolSize = (mSize - mHeader->stringsStart) / charSize;
} else {
// check invariant: styles starts before end of data
- if (mHeader->stylesStart >= (mHeader->header.size-sizeof(uint16_t))) {
+ if (mHeader->stylesStart >= (mSize - sizeof(uint16_t))) {
ALOGW("Bad style block: style block starts at %d past data size of %d\n",
(int)mHeader->stylesStart, (int)mHeader->header.size);
return (mError=BAD_TYPE);
@@ -3368,6 +3371,12 @@ status_t ResTable::addInternal(const void* data, size_t dataSize, const void* id
return NO_ERROR;
}
+ if (dataSize < sizeof(ResTable_header)) {
+ ALOGE("Invalid data. Size(%d) is smaller than a ResTable_header(%d).",
+ (int) dataSize, (int) sizeof(ResTable_header));
+ return UNKNOWN_ERROR;
+ }
+
Header* header = new Header(this);
header->index = mHeaders.size();
header->cookie = cookie;
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index d6dc6ad..5808aac 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -82,6 +82,9 @@
// Turn on to insert an event marker for each display list op
#define DEBUG_DISPLAY_LIST_OPS_AS_EVENTS 0
+// Turn on to insert detailed event markers
+#define DEBUG_DETAILED_EVENTS 0
+
// Turn on to highlight drawing batches and merged batches with different colors
#define DEBUG_MERGE_BEHAVIOR 0
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 73a4da5..d05cabc 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -88,6 +88,8 @@ bool Layer::resize(const uint32_t width, const uint32_t height) {
return true;
}
+ ATRACE_NAME("resizeLayer");
+
const uint32_t maxTextureSize = caches.maxTextureSize;
if (desiredWidth > maxTextureSize || desiredHeight > maxTextureSize) {
ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)",
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index a92ef94..e3b0daf 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "OpenGLRenderer"
+#define ATRACE_TAG ATRACE_TAG_VIEW
#include <ui/Rect.h>
@@ -184,6 +185,7 @@ void LayerRenderer::generateMesh() {
///////////////////////////////////////////////////////////////////////////////
Layer* LayerRenderer::createRenderLayer(RenderState& renderState, uint32_t width, uint32_t height) {
+ ATRACE_CALL();
LAYER_RENDERER_LOGD("Requesting new render layer %dx%d", width, height);
Caches& caches = Caches::getInstance();
@@ -309,6 +311,7 @@ void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t he
void LayerRenderer::destroyLayer(Layer* layer) {
if (layer) {
+ ATRACE_CALL();
LAYER_RENDERER_LOGD("Recycling layer, %dx%d fbo = %d",
layer->getWidth(), layer->getHeight(), layer->getFbo());
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 41f89c2..de777f0 100755
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -45,6 +45,12 @@
#include "Vector.h"
#include "VertexBuffer.h"
+#if DEBUG_DETAILED_EVENTS
+ #define EVENT_LOGD(...) eventMarkDEBUG(__VA_ARGS__)
+#else
+ #define EVENT_LOGD(...)
+#endif
+
namespace android {
namespace uirenderer {
@@ -389,6 +395,21 @@ status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
// Debug
///////////////////////////////////////////////////////////////////////////////
+void OpenGLRenderer::eventMarkDEBUG(const char* fmt, ...) const {
+#if DEBUG_DETAILED_EVENTS
+ const int BUFFER_SIZE = 256;
+ va_list ap;
+ char buf[BUFFER_SIZE];
+
+ va_start(ap, fmt);
+ vsnprintf(buf, BUFFER_SIZE, fmt, ap);
+ va_end(ap);
+
+ eventMark(buf);
+#endif
+}
+
+
void OpenGLRenderer::eventMark(const char* name) const {
mCaches.eventMark(0, name);
}
@@ -977,7 +998,13 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
}
void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
- if (!layer->isTextureLayer()) {
+ if (layer->isTextureLayer()) {
+ EVENT_LOGD("composeTextureLayerRect");
+ resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
+ drawTextureLayer(layer, rect);
+ resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
+ } else {
+ EVENT_LOGD("composeHardwareLayerRect");
const Rect& texCoords = layer->texCoords;
resetDrawTextureTexCoords(texCoords.left, texCoords.top,
texCoords.right, texCoords.bottom);
@@ -1012,10 +1039,6 @@ void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap)
GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
- } else {
- resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
- drawTextureLayer(layer, rect);
- resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
}
}
@@ -1115,6 +1138,7 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
return;
}
+ EVENT_LOGD("composeLayerRegion");
// standard Region based draw
size_t count;
const android::Rect* rects;
@@ -1288,6 +1312,7 @@ void OpenGLRenderer::clearLayerRegions() {
if (count == 0) return;
if (!currentSnapshot()->isIgnored()) {
+ EVENT_LOGD("clearLayerRegions");
// Doing several glScissor/glClear here can negatively impact
// GPUs with a tiler architecture, instead we draw quads with
// the Clear blending mode
@@ -1465,6 +1490,8 @@ void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {
void OpenGLRenderer::setStencilFromClip() {
if (!mCaches.debugOverdraw) {
if (!currentSnapshot()->clipRegion->isEmpty()) {
+ EVENT_LOGD("setStencilFromClip - enabling");
+
// NOTE: The order here is important, we must set dirtyClip to false
// before any draw call to avoid calling back into this method
mDirtyClip = false;
@@ -1510,6 +1537,7 @@ void OpenGLRenderer::setStencilFromClip() {
drawRegionRects(*(currentSnapshot()->clipRegion), paint);
}
} else {
+ EVENT_LOGD("setStencilFromClip - disabling");
mCaches.stencil.disable();
}
}
@@ -1561,17 +1589,24 @@ void OpenGLRenderer::debugClip() {
// Drawing commands
///////////////////////////////////////////////////////////////////////////////
-void OpenGLRenderer::setupDraw(bool clear) {
+void OpenGLRenderer::setupDraw(bool clearLayer) {
// TODO: It would be best if we could do this before quickRejectSetupScissor()
// changes the scissor test state
- if (clear) clearLayerRegions();
+ if (clearLayer) clearLayerRegions();
// Make sure setScissor & setStencil happen at the beginning of
// this method
if (mDirtyClip) {
if (mCaches.scissorEnabled) {
setScissorFromClip();
}
- setStencilFromClip();
+
+ if (clearLayer) {
+ setStencilFromClip();
+ } else {
+ // While clearing layer, force disable stencil buffer, since
+ // it's invalid to stencil-clip *during* the layer clear
+ mCaches.stencil.disable();
+ }
}
mDescription.reset();
@@ -2964,6 +2999,9 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
return DrawGlInfo::kStatusDone;
}
+ EVENT_LOGD("drawLayer," RECT_STRING ", clipRequired %d", x, y,
+ x + layer->layer.getWidth(), y + layer->layer.getHeight(), clipRequired);
+
updateLayer(layer, true);
mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index f698b45..3bc591f 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -256,6 +256,11 @@ public:
void eventMark(const char* name) const;
/**
+ * Inserts a formatted event marker in the stream of GL commands.
+ */
+ void eventMarkDEBUG(const char *fmt, ...) const;
+
+ /**
* Inserts a named group marker in the stream of GL commands. This marker
* can be used by tools to group commands into logical groups. A call to
* this method must always be followed later on by a call to endMark().
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 9311f99..13265a9 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -27,7 +27,7 @@
namespace android {
namespace uirenderer {
-#define RECT_STRING "%7.2f %7.2f %7.2f %7.2f"
+#define RECT_STRING "%5.2f %5.2f %5.2f %5.2f"
#define RECT_ARGS(r) \
(r).left, (r).top, (r).right, (r).bottom
#define SK_RECT_ARGS(r) \
diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp
index 140c6e8..473005c 100644
--- a/libs/hwui/StatefulBaseRenderer.cpp
+++ b/libs/hwui/StatefulBaseRenderer.cpp
@@ -178,6 +178,7 @@ bool StatefulBaseRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
SkRegion region;
region.setPath(transformed, clip);
+ // region is the transformed input path, masked by the previous clip
mDirtyClip |= mSnapshot->clipRegionTransformed(region, op);
return !mSnapshot->clipRect->isEmpty();
}
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index ec9e30a..3b8a9a4 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "OpenGLRenderer"
+#define ATRACE_TAG ATRACE_TAG_VIEW
#include <GLES2/gl2.h>
@@ -265,6 +266,8 @@ void TextureCache::generateTexture(const SkBitmap* bitmap, Texture* texture, boo
return;
}
+ ATRACE_CALL();
+
// We could also enable mipmapping if both bitmap dimensions are powers
// of 2 but we'd have to deal with size changes. Let's keep this simple
const bool canMipMap = Extensions::getInstance().hasNPot();
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index b2d8ffe..099cd3f 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -413,6 +413,7 @@ public final class AudioAttributes implements Parcelable {
default:
Log.e(TAG, "Invalid stream type " + streamType + " for AudioAttributes");
}
+ mUsage = usageForLegacyStreamType(streamType);
return this;
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 1116127..ac63ea6 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3146,18 +3146,18 @@ public class AudioManager {
* Callback method called upon audio port list update.
* @param portList the updated list of audio ports
*/
- public void OnAudioPortListUpdate(AudioPort[] portList);
+ public void onAudioPortListUpdate(AudioPort[] portList);
/**
* Callback method called upon audio patch list update.
* @param patchList the updated list of audio patches
*/
- public void OnAudioPatchListUpdate(AudioPatch[] patchList);
+ public void onAudioPatchListUpdate(AudioPatch[] patchList);
/**
* Callback method called when the mediaserver dies
*/
- public void OnServiceDied();
+ public void onServiceDied();
}
/**
diff --git a/media/java/android/media/AudioPortEventHandler.java b/media/java/android/media/AudioPortEventHandler.java
index d5fea07..8d2c172 100644
--- a/media/java/android/media/AudioPortEventHandler.java
+++ b/media/java/android/media/AudioPortEventHandler.java
@@ -91,7 +91,7 @@ class AudioPortEventHandler {
case AUDIOPORT_EVENT_PORT_LIST_UPDATED:
AudioPort[] portList = ports.toArray(new AudioPort[0]);
for (int i = 0; i < listeners.size(); i++) {
- listeners.get(i).OnAudioPortListUpdate(portList);
+ listeners.get(i).onAudioPortListUpdate(portList);
}
if (msg.what == AUDIOPORT_EVENT_PORT_LIST_UPDATED) {
break;
@@ -101,13 +101,13 @@ class AudioPortEventHandler {
case AUDIOPORT_EVENT_PATCH_LIST_UPDATED:
AudioPatch[] patchList = patches.toArray(new AudioPatch[0]);
for (int i = 0; i < listeners.size(); i++) {
- listeners.get(i).OnAudioPatchListUpdate(patchList);
+ listeners.get(i).onAudioPatchListUpdate(patchList);
}
break;
case AUDIOPORT_EVENT_SERVICE_DIED:
for (int i = 0; i < listeners.size(); i++) {
- listeners.get(i).OnServiceDied();
+ listeners.get(i).onServiceDied();
}
break;
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index ae7c501..e1c6e75 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -113,8 +113,8 @@ public class AudioService extends IAudioService.Stub {
private static final String TAG = "AudioService";
- /** Debug remote control client/display feature */
- protected static final boolean DEBUG_RC = Log.isLoggable(TAG + ".RC", Log.DEBUG);
+ /** Debug audio mode */
+ protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
/** Debug volumes */
protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
@@ -1788,6 +1788,7 @@ public class AudioService extends IAudioService.Stub {
/** @see AudioManager#setMode(int) */
public void setMode(int mode, IBinder cb) {
+ if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ")"); }
if (!checkAudioSettingsPermission("setMode()")) {
return;
}
@@ -1814,6 +1815,7 @@ public class AudioService extends IAudioService.Stub {
// setModeInt() returns a valid PID if the audio mode was successfully set to
// any mode other than NORMAL.
int setModeInt(int mode, IBinder cb, int pid) {
+ if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ")"); }
int newModeOwnerPid = 0;
if (cb == null) {
Log.e(TAG, "setModeInt() called with null binder");
@@ -1840,6 +1842,10 @@ public class AudioService extends IAudioService.Stub {
hdlr = mSetModeDeathHandlers.get(0);
cb = hdlr.getBinder();
mode = hdlr.getMode();
+ if (DEBUG_MODE) {
+ Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
+ + hdlr.mPid);
+ }
}
} else {
if (hdlr == null) {
@@ -1862,6 +1868,7 @@ public class AudioService extends IAudioService.Stub {
if (mode != mMode) {
status = AudioSystem.setPhoneState(mode);
if (status == AudioSystem.AUDIO_STATUS_OK) {
+ if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
mMode = mode;
} else {
if (hdlr != null) {
@@ -1869,6 +1876,7 @@ public class AudioService extends IAudioService.Stub {
cb.unlinkToDeath(hdlr, 0);
}
// force reading new top of mSetModeDeathHandlers stack
+ if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
mode = AudioSystem.MODE_NORMAL;
}
} else {
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index a1ccf60..c6586c0 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -483,6 +483,9 @@ public final class MediaFormat {
*/
public static final String KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
+ /** @hide */
+ public static final String KEY_IS_TIMED_TEXT = "is-timed-text";
+
/* package private */ MediaFormat(Map<String, Object> map) {
mMap = map;
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index d9217a0..2962460 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -18,6 +18,7 @@ package android.media;
import android.app.ActivityThread;
import android.app.AppOpsManager;
+import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -36,6 +37,8 @@ import android.os.Process;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.system.ErrnoException;
+import android.system.OsConstants;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
@@ -44,15 +47,22 @@ import android.media.AudioManager;
import android.media.MediaFormat;
import android.media.MediaTimeProvider;
import android.media.SubtitleController;
+import android.media.SubtitleController.Anchor;
import android.media.SubtitleData;
+import android.media.SubtitleTrack.RenderingWidget;
import com.android.internal.app.IAppOpsService;
+import libcore.io.IoBridge;
+import libcore.io.Libcore;
+
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.lang.Runnable;
import java.net.InetSocketAddress;
import java.util.Map;
@@ -1108,7 +1118,12 @@ public class MediaPlayer implements SubtitleController.Listener
*
* @throws IllegalStateException if it is called in an invalid state
*/
- public native void prepare() throws IOException, IllegalStateException;
+ public void prepare() throws IOException, IllegalStateException {
+ _prepare();
+ scanInternalSubtitleTracks();
+ }
+
+ private native void _prepare() throws IOException, IllegalStateException;
/**
* Prepares the player for playback, asynchronously.
@@ -1846,7 +1861,10 @@ public class MediaPlayer implements SubtitleController.Listener
System.arraycopy(trackInfo, 0, allTrackInfo, 0, trackInfo.length);
int i = trackInfo.length;
for (SubtitleTrack track: mOutOfBandSubtitleTracks) {
- allTrackInfo[i] = new TrackInfo(TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE, track.getFormat());
+ int type = track.isTimedText()
+ ? TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT
+ : TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE;
+ allTrackInfo[i] = new TrackInfo(type, track.getFormat());
++i;
}
return allTrackInfo;
@@ -1891,7 +1909,7 @@ public class MediaPlayer implements SubtitleController.Listener
* A helper function to check if the mime type is supported by media framework.
*/
private static boolean availableMimeTypeForExternalSource(String mimeType) {
- if (mimeType == MEDIA_MIMETYPE_TEXT_SUBRIP) {
+ if (MEDIA_MIMETYPE_TEXT_SUBRIP.equals(mimeType)) {
return true;
}
return false;
@@ -2147,27 +2165,97 @@ public class MediaPlayer implements SubtitleController.Listener
* @throws IllegalArgumentException if the mimeType is not supported.
* @throws IllegalStateException if called in an invalid state.
*/
- public void addTimedTextSource(FileDescriptor fd, long offset, long length, String mimeType)
+ public void addTimedTextSource(FileDescriptor fd, long offset, long length, String mime)
throws IllegalArgumentException, IllegalStateException {
- if (!availableMimeTypeForExternalSource(mimeType)) {
- throw new IllegalArgumentException("Illegal mimeType for timed text source: " + mimeType);
-
+ if (!availableMimeTypeForExternalSource(mime)) {
+ throw new IllegalArgumentException("Illegal mimeType for timed text source: " + mime);
}
- Parcel request = Parcel.obtain();
- Parcel reply = Parcel.obtain();
+ FileDescriptor fd2;
try {
- request.writeInterfaceToken(IMEDIA_PLAYER);
- request.writeInt(INVOKE_ID_ADD_EXTERNAL_SOURCE_FD);
- request.writeFileDescriptor(fd);
- request.writeLong(offset);
- request.writeLong(length);
- request.writeString(mimeType);
- invoke(request, reply);
- } finally {
- request.recycle();
- reply.recycle();
+ fd2 = Libcore.os.dup(fd);
+ } catch (ErrnoException ex) {
+ Log.e(TAG, ex.getMessage(), ex);
+ throw new RuntimeException(ex);
}
+
+ final MediaFormat fFormat = new MediaFormat();
+ fFormat.setString(MediaFormat.KEY_MIME, mime);
+ fFormat.setInteger(MediaFormat.KEY_IS_TIMED_TEXT, 1);
+
+ Context context = ActivityThread.currentApplication();
+ // A MediaPlayer created by a VideoView should already have its mSubtitleController set.
+ if (mSubtitleController == null) {
+ mSubtitleController = new SubtitleController(context, mTimeProvider, this);
+ mSubtitleController.setAnchor(new Anchor() {
+ @Override
+ public void setSubtitleWidget(RenderingWidget subtitleWidget) {
+ }
+
+ @Override
+ public Looper getSubtitleLooper() {
+ return Looper.getMainLooper();
+ }
+ });
+ }
+
+ if (!mSubtitleController.hasRendererFor(fFormat)) {
+ // test and add not atomic
+ mSubtitleController.registerRenderer(new SRTRenderer(context, mEventHandler));
+ }
+ final SubtitleTrack track = mSubtitleController.addTrack(fFormat);
+ mOutOfBandSubtitleTracks.add(track);
+
+ final FileDescriptor fd3 = fd2;
+ final long offset2 = offset;
+ final long length2 = length;
+ final HandlerThread thread = new HandlerThread(
+ "TimedTextReadThread",
+ Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
+ thread.start();
+ Handler handler = new Handler(thread.getLooper());
+ handler.post(new Runnable() {
+ private int addTrack() {
+ InputStream is = null;
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ try {
+ Libcore.os.lseek(fd3, offset2, OsConstants.SEEK_SET);
+ byte[] buffer = new byte[4096];
+ for (int total = 0; total < length2;) {
+ int remain = (int)length2 - total;
+ int bytes = IoBridge.read(fd3, buffer, 0, Math.min(buffer.length, remain));
+ if (bytes < 0) {
+ break;
+ } else {
+ bos.write(buffer, 0, bytes);
+ total += bytes;
+ }
+ }
+ track.onData(bos.toByteArray(), true /* eos */, ~0 /* runID: keep forever */);
+ return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
+ } catch (Exception e) {
+ Log.e(TAG, e.getMessage(), e);
+ return MEDIA_INFO_TIMED_TEXT_ERROR;
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ Log.e(TAG, e.getMessage(), e);
+ }
+ }
+ }
+ }
+
+ public void run() {
+ int res = addTrack();
+ if (mEventHandler != null) {
+ Message m = mEventHandler.obtainMessage(MEDIA_INFO, res, 0, null);
+ mEventHandler.sendMessage(m);
+ }
+ thread.getLooper().quitSafely();
+ }
+ });
}
/**
@@ -2275,6 +2363,13 @@ public class MediaPlayer implements SubtitleController.Listener
if (mSubtitleController != null && track != null) {
if (select) {
+ if (track.isTimedText()) {
+ int ttIndex = getSelectedTrack(TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT);
+ if (ttIndex >= 0 && ttIndex < mInbandSubtitleTracks.length) {
+ // deselect inband counterpart
+ selectOrDeselectInbandTrack(ttIndex, false);
+ }
+ }
mSubtitleController.selectTrack(track);
} else if (mSubtitleController.getSelectedTrack() == track) {
mSubtitleController.selectTrack(null);
diff --git a/media/java/android/media/SRTRenderer.java b/media/java/android/media/SRTRenderer.java
new file mode 100644
index 0000000..ee4edee
--- /dev/null
+++ b/media/java/android/media/SRTRenderer.java
@@ -0,0 +1,202 @@
+package android.media;
+
+import android.content.Context;
+import android.media.SubtitleController.Renderer;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Parcel;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Vector;
+
+/** @hide */
+public class SRTRenderer extends Renderer {
+ private final Context mContext;
+ private final boolean mRender;
+ private final Handler mEventHandler;
+
+ private WebVttRenderingWidget mRenderingWidget;
+
+ public SRTRenderer(Context context) {
+ this(context, null);
+ }
+
+ SRTRenderer(Context mContext, Handler mEventHandler) {
+ this.mContext = mContext;
+ this.mRender = (mEventHandler == null);
+ this.mEventHandler = mEventHandler;
+ }
+
+ @Override
+ public boolean supports(MediaFormat format) {
+ if (format.containsKey(MediaFormat.KEY_MIME)) {
+ if (!format.getString(MediaFormat.KEY_MIME)
+ .equals(MediaPlayer.MEDIA_MIMETYPE_TEXT_SUBRIP)) {
+ return false;
+ };
+ return mRender == (format.getInteger(MediaFormat.KEY_IS_TIMED_TEXT, 0) == 0);
+ }
+ return false;
+ }
+
+ @Override
+ public SubtitleTrack createTrack(MediaFormat format) {
+ if (mRender && mRenderingWidget == null) {
+ mRenderingWidget = new WebVttRenderingWidget(mContext);
+ }
+
+ if (mRender) {
+ return new SRTTrack(mRenderingWidget, format);
+ } else {
+ return new SRTTrack(mEventHandler, format);
+ }
+ }
+}
+
+class SRTTrack extends WebVttTrack {
+ private static final int MEDIA_TIMED_TEXT = 99; // MediaPlayer.MEDIA_TIMED_TEXT
+ private static final int KEY_STRUCT_TEXT = 16; // TimedText.KEY_STRUCT_TEXT
+ private static final int KEY_START_TIME = 7; // TimedText.KEY_START_TIME
+ private static final int KEY_LOCAL_SETTING = 102; // TimedText.KEY_START_TIME
+
+ private static final String TAG = "SRTTrack";
+ private final Handler mEventHandler;
+
+ SRTTrack(WebVttRenderingWidget renderingWidget, MediaFormat format) {
+ super(renderingWidget, format);
+ mEventHandler = null;
+ }
+
+ SRTTrack(Handler eventHandler, MediaFormat format) {
+ super(null, format);
+ mEventHandler = eventHandler;
+ }
+
+ @Override
+ protected void onData(SubtitleData data) {
+ try {
+ TextTrackCue cue = new TextTrackCue();
+ cue.mStartTimeMs = data.getStartTimeUs() / 1000;
+ cue.mEndTimeMs = (data.getStartTimeUs() + data.getDurationUs()) / 1000;
+
+ String paragraph;
+ paragraph = new String(data.getData(), "UTF-8");
+ String[] lines = paragraph.split("\\r?\\n");
+ cue.mLines = new TextTrackCueSpan[lines.length][];
+
+ int i = 0;
+ for (String line : lines) {
+ TextTrackCueSpan[] span = new TextTrackCueSpan[] {
+ new TextTrackCueSpan(line, -1)
+ };
+ cue.mLines[i++] = span;
+ }
+
+ addCue(cue);
+ } catch (UnsupportedEncodingException e) {
+ Log.w(TAG, "subtitle data is not UTF-8 encoded: " + e);
+ }
+ }
+
+ @Override
+ public void onData(byte[] data, boolean eos, long runID) {
+ // TODO make reentrant
+ try {
+ Reader r = new InputStreamReader(new ByteArrayInputStream(data), "UTF-8");
+ BufferedReader br = new BufferedReader(r);
+
+ String header;
+ while ((header = br.readLine()) != null) {
+ // discard subtitle number
+ header = br.readLine();
+ if (header == null) {
+ break;
+ }
+
+ TextTrackCue cue = new TextTrackCue();
+ String[] startEnd = header.split("-->");
+ cue.mStartTimeMs = parseMs(startEnd[0]);
+ cue.mEndTimeMs = parseMs(startEnd[1]);
+
+ String s;
+ List<String> paragraph = new ArrayList<String>();
+ while (!((s = br.readLine()) == null || s.trim().equals(""))) {
+ paragraph.add(s);
+ }
+
+ int i = 0;
+ cue.mLines = new TextTrackCueSpan[paragraph.size()][];
+ cue.mStrings = paragraph.toArray(new String[0]);
+ for (String line : paragraph) {
+ TextTrackCueSpan[] span = new TextTrackCueSpan[] {
+ new TextTrackCueSpan(line, -1)
+ };
+ cue.mStrings[i] = line;
+ cue.mLines[i++] = span;
+ }
+
+ addCue(cue);
+ }
+
+ } catch (UnsupportedEncodingException e) {
+ Log.w(TAG, "subtitle data is not UTF-8 encoded: " + e);
+ } catch (IOException ioe) {
+ // shouldn't happen
+ Log.e(TAG, ioe.getMessage(), ioe);
+ }
+ }
+
+ @Override
+ public void updateView(Vector<Cue> activeCues) {
+ if (getRenderingWidget() != null) {
+ super.updateView(activeCues);
+ return;
+ }
+
+ if (mEventHandler == null) {
+ return;
+ }
+
+ final int _ = 0;
+ for (Cue cue : activeCues) {
+ TextTrackCue ttc = (TextTrackCue) cue;
+
+ Parcel parcel = Parcel.obtain();
+ parcel.writeInt(KEY_LOCAL_SETTING);
+ parcel.writeInt(KEY_START_TIME);
+ parcel.writeInt((int) cue.mStartTimeMs);
+
+ parcel.writeInt(KEY_STRUCT_TEXT);
+ StringBuilder sb = new StringBuilder();
+ for (String line : ttc.mStrings) {
+ sb.append(line).append('\n');
+ }
+
+ byte[] buf = sb.toString().getBytes();
+ parcel.writeInt(buf.length);
+ parcel.writeByteArray(buf);
+
+ Message msg = mEventHandler.obtainMessage(MEDIA_TIMED_TEXT, _, _, parcel);
+ mEventHandler.sendMessage(msg);
+ }
+ activeCues.clear();
+ }
+
+ private static long parseMs(String in) {
+ long hours = Long.parseLong(in.split(":")[0].trim());
+ long minutes = Long.parseLong(in.split(":")[1].trim());
+ long seconds = Long.parseLong(in.split(":")[2].split(",")[0].trim());
+ long millies = Long.parseLong(in.split(":")[2].split(",")[1].trim());
+
+ return hours * 60 * 60 * 1000 + minutes * 60 * 1000 + seconds * 1000 + millies;
+
+ }
+}
diff --git a/media/java/android/media/SubtitleController.java b/media/java/android/media/SubtitleController.java
index 13205bc..37adb8c 100644
--- a/media/java/android/media/SubtitleController.java
+++ b/media/java/android/media/SubtitleController.java
@@ -420,6 +420,19 @@ public class SubtitleController {
}
}
+ /** @hide */
+ public boolean hasRendererFor(MediaFormat format) {
+ synchronized(mRenderers) {
+ // TODO how to get available renderers in the system
+ for (Renderer renderer: mRenderers) {
+ if (renderer.supports(format)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
/**
* Subtitle anchor, an object that is able to display a subtitle renderer,
* e.g. a VideoView.
diff --git a/media/java/android/media/SubtitleTrack.java b/media/java/android/media/SubtitleTrack.java
index 9fedf63..c760810 100644
--- a/media/java/android/media/SubtitleTrack.java
+++ b/media/java/android/media/SubtitleTrack.java
@@ -274,7 +274,10 @@ public abstract class SubtitleTrack implements MediaTimeProvider.OnMediaTimeList
}
mVisible = true;
- getRenderingWidget().setVisible(true);
+ RenderingWidget renderingWidget = getRenderingWidget();
+ if (renderingWidget != null) {
+ renderingWidget.setVisible(true);
+ }
if (mTimeProvider != null) {
mTimeProvider.scheduleUpdate(this);
}
@@ -289,7 +292,10 @@ public abstract class SubtitleTrack implements MediaTimeProvider.OnMediaTimeList
if (mTimeProvider != null) {
mTimeProvider.cancelNotifications(this);
}
- getRenderingWidget().setVisible(false);
+ RenderingWidget renderingWidget = getRenderingWidget();
+ if (renderingWidget != null) {
+ renderingWidget.setVisible(false);
+ }
mVisible = false;
}
@@ -602,6 +608,12 @@ public abstract class SubtitleTrack implements MediaTimeProvider.OnMediaTimeList
}
}
+ /** @hide whether this is a text track who fires events instead getting rendered */
+ public boolean isTimedText() {
+ return getRenderingWidget() == null;
+ }
+
+
/** @hide */
private static class Run {
public Cue mFirstCue;
diff --git a/media/java/android/media/WebVttRenderer.java b/media/java/android/media/WebVttRenderer.java
index a9374d5..69e0ea6 100644
--- a/media/java/android/media/WebVttRenderer.java
+++ b/media/java/android/media/WebVttRenderer.java
@@ -1098,7 +1098,9 @@ class WebVttTrack extends SubtitleTrack implements WebVttCueListener {
}
}
- mRenderingWidget.setActiveCues(activeCues);
+ if (mRenderingWidget != null) {
+ mRenderingWidget.setActiveCues(activeCues);
+ }
}
}
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 348a577..7c03171 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -160,9 +160,10 @@ public final class MediaProjection {
public static abstract class Callback {
/**
* Called when the MediaProjection session is no longer valid.
- *
+ * <p>
* Once a MediaProjection has been stopped, it's up to the application to release any
* resources it may be holding (e.g. {@link android.hardware.display.VirtualDisplay}s).
+ * </p>
*/
public void onStop() { }
}
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 4587cf5..73a924d 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -861,7 +861,7 @@ static JNINativeMethod gMethods[] = {
{"_setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD},
{"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer_setVideoSurface},
- {"prepare", "()V", (void *)android_media_MediaPlayer_prepare},
+ {"_prepare", "()V", (void *)android_media_MediaPlayer_prepare},
{"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync},
{"_start", "()V", (void *)android_media_MediaPlayer_start},
{"_stop", "()V", (void *)android_media_MediaPlayer_stop},
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index a26c534..0f8fe1c 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -359,8 +359,8 @@ public class ExpandHelper implements Gefingerpoken {
}
private void maybeRecycleVelocityTracker(MotionEvent event) {
- if (event.getActionMasked() == MotionEvent.ACTION_CANCEL
- || event.getActionMasked() == MotionEvent.ACTION_UP) {
+ if (mVelocityTracker != null && (event.getActionMasked() == MotionEvent.ACTION_CANCEL
+ || event.getActionMasked() == MotionEvent.ACTION_UP)) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index b80a33b..1932843 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -937,12 +937,16 @@ public class NotificationPanelView extends PanelView implements
}
private void updateNotificationTranslucency() {
float alpha = (getNotificationsTopY() + mNotificationStackScroller.getItemHeight())
- / (mQsMinExpansionHeight + mNotificationStackScroller.getItemHeight() / 2);
+ / (mQsMinExpansionHeight + mNotificationStackScroller.getBottomStackPeekSize()
+ + mNotificationStackScroller.getCollapseSecondCardPadding());
alpha = Math.max(0, Math.min(alpha, 1));
alpha = (float) Math.pow(alpha, 0.75);
-
- // TODO: Draw a rect with DST_OUT over the notifications to achieve the same effect -
- // this would be much more efficient.
+ if (alpha != 1f && mNotificationStackScroller.getLayerType() != LAYER_TYPE_HARDWARE) {
+ mNotificationStackScroller.setLayerType(LAYER_TYPE_HARDWARE, null);
+ } else if (alpha == 1f
+ && mNotificationStackScroller.getLayerType() == LAYER_TYPE_HARDWARE) {
+ mNotificationStackScroller.setLayerType(LAYER_TYPE_NONE, null);
+ }
mNotificationStackScroller.setAlpha(alpha);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 9b819f2..e0167e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -470,6 +470,10 @@ public class NotificationStackScrollLayout extends ViewGroup
return mBottomStackPeekSize;
}
+ public int getCollapseSecondCardPadding() {
+ return mCollapseSecondCardPadding;
+ }
+
public void setLongPressListener(SwipeHelper.LongPressListener listener) {
mSwipeHelper.setLongPressListener(listener);
mLongPressListener = listener;
@@ -1955,8 +1959,10 @@ public class NotificationStackScrollLayout extends ViewGroup
}
public void setScrimAlpha(float progress) {
- mAmbientState.setScrimAmount(progress);
- requestChildrenUpdate();
+ if (progress != mAmbientState.getScrimAmount()) {
+ mAmbientState.setScrimAmount(progress);
+ requestChildrenUpdate();
+ }
}
/**
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 9659b79..d434d7a 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -3151,6 +3151,13 @@ public class BackupManagerService extends IBackupManager.Stub {
FileOutputStream outstream = new FileOutputStream(manifestFile);
outstream.write(builder.toString().getBytes());
outstream.close();
+
+ // We want the manifest block in the archive stream to be idempotent:
+ // each time we generate a backup stream for the app, we want the manifest
+ // block to be identical. The underlying tar mechanism sees it as a file,
+ // though, and will propagate its mtime, causing the tar header to vary.
+ // Avoid this problem by pinning the mtime to zero.
+ manifestFile.setLastModified(0);
}
// Widget metadata format. All header entries are strings ending in LF:
@@ -3188,6 +3195,10 @@ public class BackupManagerService extends IBackupManager.Stub {
}
bout.flush();
out.close();
+
+ // As with the manifest file, guarantee idempotence of the archive metadata
+ // for the widget block by using a fixed mtime on the transient file.
+ destination.setLastModified(0);
}
private void tearDown(PackageInfo pkg) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index cc2167d..7aa69fd 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1296,172 +1296,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
"ConnectivityService");
}
- /**
- * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
- * network, we ignore it. If it is for the active network, we send out a
- * broadcast. But first, we check whether it might be possible to connect
- * to a different network.
- * @param info the {@code NetworkInfo} for the network
- */
- private void handleDisconnect(NetworkInfo info) {
-
- int prevNetType = info.getType();
-
- mNetTrackers[prevNetType].setTeardownRequested(false);
- int thisNetId = mNetTrackers[prevNetType].getNetwork().netId;
-
- // Remove idletimer previously setup in {@code handleConnect}
-// Already in place in new function. This is dead code.
-// if (mNetConfigs[prevNetType].isDefault()) {
-// removeDataActivityTracking(prevNetType);
-// }
-
- /*
- * If the disconnected network is not the active one, then don't report
- * this as a loss of connectivity. What probably happened is that we're
- * getting the disconnect for a network that we explicitly disabled
- * in accordance with network preference policies.
- */
-// if (!mNetConfigs[prevNetType].isDefault()) {
-// List<Integer> pids = mNetRequestersPids[prevNetType];
-// for (Integer pid : pids) {
-// // will remove them because the net's no longer connected
-// // need to do this now as only now do we know the pids and
-// // can properly null things that are no longer referenced.
-// reassessPidDns(pid.intValue(), false);
-// }
-// }
-
- Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info));
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
- if (info.isFailover()) {
- intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
- info.setFailover(false);
- }
- if (info.getReason() != null) {
- intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
- }
- if (info.getExtraInfo() != null) {
- intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
- info.getExtraInfo());
- }
-
- if (mNetConfigs[prevNetType].isDefault()) {
- tryFailover(prevNetType);
- if (mActiveDefaultNetwork != -1) {
- NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
- intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
- } else {
- mDefaultInetConditionPublished = 0; // we're not connected anymore
- intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
- }
- }
- intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
-
- // Reset interface if no other connections are using the same interface
- boolean doReset = true;
- LinkProperties linkProperties = mNetTrackers[prevNetType].getLinkProperties();
- if (linkProperties != null) {
- String oldIface = linkProperties.getInterfaceName();
- if (TextUtils.isEmpty(oldIface) == false) {
- for (NetworkStateTracker networkStateTracker : mNetTrackers) {
- if (networkStateTracker == null) continue;
- NetworkInfo networkInfo = networkStateTracker.getNetworkInfo();
- if (networkInfo.isConnected() && networkInfo.getType() != prevNetType) {
- LinkProperties l = networkStateTracker.getLinkProperties();
- if (l == null) continue;
- if (oldIface.equals(l.getInterfaceName())) {
- doReset = false;
- break;
- }
- }
- }
- }
- }
-
- // do this before we broadcast the change
-// Already done in new function. This is dead code.
-// handleConnectivityChange(prevNetType, doReset);
-
- final Intent immediateIntent = new Intent(intent);
- immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
- sendStickyBroadcast(immediateIntent);
- sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay());
- /*
- * If the failover network is already connected, then immediately send
- * out a followup broadcast indicating successful failover
- */
- if (mActiveDefaultNetwork != -1) {
- sendConnectedBroadcastDelayed(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(),
- getConnectivityChangeDelay());
- }
- try {
-// mNetd.removeNetwork(thisNetId);
- } catch (Exception e) {
- loge("Exception removing network: " + e);
- } finally {
-// mNetTrackers[prevNetType].setNetId(INVALID_NET_ID);
- }
- }
-
- private void tryFailover(int prevNetType) {
- /*
- * If this is a default network, check if other defaults are available.
- * Try to reconnect on all available and let them hash it out when
- * more than one connects.
- */
- if (mNetConfigs[prevNetType].isDefault()) {
- if (mActiveDefaultNetwork == prevNetType) {
- if (DBG) {
- log("tryFailover: set mActiveDefaultNetwork=-1, prevNetType=" + prevNetType);
- }
- mActiveDefaultNetwork = -1;
- try {
- mNetd.clearDefaultNetId();
- } catch (Exception e) {
- loge("Exception clearing default network :" + e);
- }
- }
-
- // don't signal a reconnect for anything lower or equal priority than our
- // current connected default
- // TODO - don't filter by priority now - nice optimization but risky
-// int currentPriority = -1;
-// if (mActiveDefaultNetwork != -1) {
-// currentPriority = mNetConfigs[mActiveDefaultNetwork].mPriority;
-// }
-
- for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
- if (checkType == prevNetType) continue;
- if (mNetConfigs[checkType] == null) continue;
- if (!mNetConfigs[checkType].isDefault()) continue;
- if (mNetTrackers[checkType] == null) continue;
-
-// Enabling the isAvailable() optimization caused mobile to not get
-// selected if it was in the middle of error handling. Specifically
-// a moble connection that took 30 seconds to complete the DEACTIVATE_DATA_CALL
-// would not be available and we wouldn't get connected to anything.
-// So removing the isAvailable() optimization below for now. TODO: This
-// optimization should work and we need to investigate why it doesn't work.
-// This could be related to how DEACTIVATE_DATA_CALL is reporting its
-// complete before it is really complete.
-
-// if (!mNetTrackers[checkType].isAvailable()) continue;
-
-// if (currentPriority >= mNetConfigs[checkType].mPriority) continue;
-
- NetworkStateTracker checkTracker = mNetTrackers[checkType];
- NetworkInfo checkInfo = checkTracker.getNetworkInfo();
- if (!checkInfo.isConnectedOrConnecting() || checkTracker.isTeardownRequested()) {
- checkInfo.setFailover(true);
- checkTracker.reconnect();
- }
- if (DBG) log("Attempting to switch to " + checkInfo.getTypeName());
- }
- }
- }
-
public void sendConnectedBroadcast(NetworkInfo info) {
enforceConnectivityInternalPermission();
sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
@@ -1597,125 +1431,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
};
- private boolean isNewNetTypePreferredOverCurrentNetType(int type) {
- if (((type != mNetworkPreference)
- && (mNetConfigs[mActiveDefaultNetwork].priority > mNetConfigs[type].priority))
- || (mNetworkPreference == mActiveDefaultNetwork)) {
- return false;
- }
- return true;
- }
-
- private void handleConnect(NetworkInfo info) {
- final int newNetType = info.getType();
-
- // snapshot isFailover, because sendConnectedBroadcast() resets it
- boolean isFailover = info.isFailover();
- final NetworkStateTracker thisNet = mNetTrackers[newNetType];
- final String thisIface = thisNet.getLinkProperties().getInterfaceName();
-
- if (VDBG) {
- log("handleConnect: E newNetType=" + newNetType + " thisIface=" + thisIface
- + " isFailover" + isFailover);
- }
-
- // if this is a default net and other default is running
- // kill the one not preferred
- if (mNetConfigs[newNetType].isDefault()) {
- if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != newNetType) {
- if (isNewNetTypePreferredOverCurrentNetType(newNetType)) {
- String teardownPolicy = SystemProperties.get("net.teardownPolicy");
- if (TextUtils.equals(teardownPolicy, "keep") == false) {
- // tear down the other
- NetworkStateTracker otherNet =
- mNetTrackers[mActiveDefaultNetwork];
- if (DBG) {
- log("Policy requires " + otherNet.getNetworkInfo().getTypeName() +
- " teardown");
- }
- if (!teardown(otherNet)) {
- loge("Network declined teardown request");
- teardown(thisNet);
- return;
- }
- } else {
- //TODO - remove
- loge("network teardown skipped due to net.teardownPolicy setting");
- }
- } else {
- // don't accept this one
- if (VDBG) {
- log("Not broadcasting CONNECT_ACTION " +
- "to torn down network " + info.getTypeName());
- }
- teardown(thisNet);
- return;
- }
- }
- int thisNetId = nextNetId();
- thisNet.setNetId(thisNetId);
- try {
-// mNetd.createNetwork(thisNetId, thisIface);
- } catch (Exception e) {
- loge("Exception creating network :" + e);
- teardown(thisNet);
- return;
- }
-// Already in place in new function. This is dead code.
-// setupDataActivityTracking(newNetType);
- synchronized (ConnectivityService.this) {
- // have a new default network, release the transition wakelock in a second
- // if it's held. The second pause is to allow apps to reconnect over the
- // new network
- if (mNetTransitionWakeLock.isHeld()) {
- mHandler.sendMessageDelayed(mHandler.obtainMessage(
- EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
- mNetTransitionWakeLockSerialNumber, 0),
- 1000);
- }
- }
- mActiveDefaultNetwork = newNetType;
- try {
- mNetd.setDefaultNetId(thisNetId);
- } catch (Exception e) {
- loge("Exception setting default network :" + e);
- }
- // this will cause us to come up initially as unconnected and switching
- // to connected after our normal pause unless somebody reports us as reall
- // disconnected
- mDefaultInetConditionPublished = 0;
- mDefaultConnectionSequence++;
- mInetConditionChangeInFlight = false;
- // Don't do this - if we never sign in stay, grey
- //reportNetworkCondition(mActiveDefaultNetwork, 100);
- updateNetworkSettings(thisNet);
- } else {
- int thisNetId = nextNetId();
- thisNet.setNetId(thisNetId);
- try {
-// mNetd.createNetwork(thisNetId, thisIface);
- } catch (Exception e) {
- loge("Exception creating network :" + e);
- teardown(thisNet);
- return;
- }
- }
- thisNet.setTeardownRequested(false);
-// Already in place in new function. This is dead code.
-// updateMtuSizeSettings(thisNet);
-// handleConnectivityChange(newNetType, false);
- sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
-
- // notify battery stats service about this network
- if (thisIface != null) {
- try {
- BatteryStatsService.getService().noteNetworkInterfaceType(thisIface, newNetType);
- } catch (RemoteException e) {
- // ignored; service lives in system_server
- }
- }
- }
-
/** @hide */
@Override
public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) {
@@ -1782,199 +1497,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
/**
- * After a change in the connectivity state of a network. We're mainly
- * concerned with making sure that the list of DNS servers is set up
- * according to which networks are connected, and ensuring that the
- * right routing table entries exist.
- *
- * TODO - delete when we're sure all this functionallity is captured.
- */
- /*
- private void handleConnectivityChange(int netType, LinkProperties curLp, boolean doReset) {
- int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
- boolean exempt = ConnectivityManager.isNetworkTypeExempt(netType);
- if (VDBG) {
- log("handleConnectivityChange: netType=" + netType + " doReset=" + doReset
- + " resetMask=" + resetMask);
- }
-
- // If a non-default network is enabled, add the host routes that
- // will allow it's DNS servers to be accessed.
- handleDnsConfigurationChange(netType);
-
- LinkProperties newLp = null;
-
- if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
- newLp = mNetTrackers[netType].getLinkProperties();
- if (VDBG) {
- log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
- " doReset=" + doReset + " resetMask=" + resetMask +
- "\n curLp=" + curLp +
- "\n newLp=" + newLp);
- }
-
- if (curLp != null) {
- if (curLp.isIdenticalInterfaceName(newLp)) {
- CompareResult<LinkAddress> car = curLp.compareAddresses(newLp);
- if ((car.removed.size() != 0) || (car.added.size() != 0)) {
- for (LinkAddress linkAddr : car.removed) {
- if (linkAddr.getAddress() instanceof Inet4Address) {
- resetMask |= NetworkUtils.RESET_IPV4_ADDRESSES;
- }
- if (linkAddr.getAddress() instanceof Inet6Address) {
- resetMask |= NetworkUtils.RESET_IPV6_ADDRESSES;
- }
- }
- if (DBG) {
- log("handleConnectivityChange: addresses changed" +
- " linkProperty[" + netType + "]:" + " resetMask=" + resetMask +
- "\n car=" + car);
- }
- } else {
- if (VDBG) {
- log("handleConnectivityChange: addresses are the same reset per" +
- " doReset linkProperty[" + netType + "]:" +
- " resetMask=" + resetMask);
- }
- }
- } else {
- resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
- if (DBG) {
- log("handleConnectivityChange: interface not not equivalent reset both" +
- " linkProperty[" + netType + "]:" +
- " resetMask=" + resetMask);
- }
- }
- }
- if (mNetConfigs[netType].isDefault()) {
- handleApplyDefaultProxy(newLp.getHttpProxy());
- }
- } else {
- if (VDBG) {
- log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
- " doReset=" + doReset + " resetMask=" + resetMask +
- "\n curLp=" + curLp +
- "\n newLp= null");
- }
- }
- mCurrentLinkProperties[netType] = newLp;
- boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt,
- mNetTrackers[netType].getNetwork().netId);
-
- if (resetMask != 0 || resetDns) {
- if (VDBG) log("handleConnectivityChange: resetting");
- if (curLp != null) {
- if (VDBG) log("handleConnectivityChange: resetting curLp=" + curLp);
- for (String iface : curLp.getAllInterfaceNames()) {
- if (TextUtils.isEmpty(iface) == false) {
- if (resetMask != 0) {
- if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")");
- NetworkUtils.resetConnections(iface, resetMask);
-
- // Tell VPN the interface is down. It is a temporary
- // but effective fix to make VPN aware of the change.
- if ((resetMask & NetworkUtils.RESET_IPV4_ADDRESSES) != 0) {
- synchronized(mVpns) {
- for (int i = 0; i < mVpns.size(); i++) {
- mVpns.valueAt(i).interfaceStatusChanged(iface, false);
- }
- }
- }
- }
- } else {
- loge("Can't reset connection for type "+netType);
- }
- }
- if (resetDns) {
- flushVmDnsCache();
- if (VDBG) log("resetting DNS cache for type " + netType);
- try {
- mNetd.flushNetworkDnsCache(mNetTrackers[netType].getNetwork().netId);
- } catch (Exception e) {
- // never crash - catch them all
- if (DBG) loge("Exception resetting dns cache: " + e);
- }
- }
- }
- }
-
- // TODO: Temporary notifying upstread change to Tethering.
- // @see bug/4455071
- // Notify TetheringService if interface name has been changed.
- if (TextUtils.equals(mNetTrackers[netType].getNetworkInfo().getReason(),
- PhoneConstants.REASON_LINK_PROPERTIES_CHANGED)) {
- if (isTetheringSupported()) {
- mTethering.handleTetherIfaceChange();
- }
- }
- }
- */
-
- /**
- * Add and remove routes using the old properties (null if not previously connected),
- * new properties (null if becoming disconnected). May even be double null, which
- * is a noop.
- * Uses isLinkDefault to determine if default routes should be set or conversely if
- * host routes should be set to the dns servers
- * returns a boolean indicating the routes changed
- */
- /*
- private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp,
- boolean isLinkDefault, boolean exempt, int netId) {
- Collection<RouteInfo> routesToAdd = null;
- CompareResult<InetAddress> dnsDiff = new CompareResult<InetAddress>();
- CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
- if (curLp != null) {
- // check for the delta between the current set and the new
- routeDiff = curLp.compareAllRoutes(newLp);
- dnsDiff = curLp.compareDnses(newLp);
- } else if (newLp != null) {
- routeDiff.added = newLp.getAllRoutes();
- dnsDiff.added = newLp.getDnsServers();
- }
-
- boolean routesChanged = (routeDiff.removed.size() != 0 || routeDiff.added.size() != 0);
-
- for (RouteInfo r : routeDiff.removed) {
- if (isLinkDefault || ! r.isDefaultRoute()) {
- if (VDBG) log("updateRoutes: default remove route r=" + r);
- removeRoute(curLp, r, TO_DEFAULT_TABLE, netId);
- }
- if (isLinkDefault == false) {
- // remove from a secondary route table
- removeRoute(curLp, r, TO_SECONDARY_TABLE, netId);
- }
- }
-
- for (RouteInfo r : routeDiff.added) {
- if (isLinkDefault || ! r.isDefaultRoute()) {
- addRoute(newLp, r, TO_DEFAULT_TABLE, exempt, netId);
- } else {
- // add to a secondary route table
- addRoute(newLp, r, TO_SECONDARY_TABLE, UNEXEMPT, netId);
-
- // many radios add a default route even when we don't want one.
- // remove the default route unless somebody else has asked for it
- String ifaceName = newLp.getInterfaceName();
- synchronized (mRoutesLock) {
- if (!TextUtils.isEmpty(ifaceName) && !mAddedRoutes.contains(r)) {
- if (VDBG) log("Removing " + r + " for interface " + ifaceName);
- try {
- mNetd.removeRoute(netId, r);
- } catch (Exception e) {
- // never crash - catch them all
- if (DBG) loge("Exception trying to remove a route: " + e);
- }
- }
- }
- }
- }
-
- return routesChanged;
- }
- */
-
- /**
* Reads the network specific MTU size from reources.
* and set it on it's iface.
*/
@@ -2080,72 +1602,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
- // Caller must grab mDnsLock.
- private void updateDnsLocked(String network, int netId,
- Collection<InetAddress> dnses, String domains) {
- int last = 0;
- if (dnses.size() == 0 && mDefaultDns != null) {
- dnses = new ArrayList();
- dnses.add(mDefaultDns);
- if (DBG) {
- loge("no dns provided for " + network + " - using " + mDefaultDns.getHostAddress());
- }
- }
-
- try {
- mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses), domains);
-
- 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;
- } catch (Exception e) {
- loge("exception setting default dns interface: " + e);
- }
- }
-
- private void handleDnsConfigurationChange(int netType) {
- // add default net's dns entries
- NetworkStateTracker nt = mNetTrackers[netType];
- if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
- LinkProperties p = nt.getLinkProperties();
- if (p == null) return;
- Collection<InetAddress> dnses = p.getDnsServers();
- int netId = nt.getNetwork().netId;
- if (mNetConfigs[netType].isDefault()) {
- String network = nt.getNetworkInfo().getTypeName();
- synchronized (mDnsLock) {
- updateDnsLocked(network, netId, dnses, p.getDomains());
- }
- } else {
- try {
- mNetd.setDnsServersForNetwork(netId,
- NetworkUtils.makeStrings(dnses), p.getDomains());
- } catch (Exception e) {
- if (DBG) loge("exception setting dns servers: " + e);
- }
- // set per-pid dns for attached secondary nets
-// List<Integer> pids = mNetRequestersPids[netType];
-// for (Integer pid : pids) {
-// try {
- // TODO: Reimplement this via local variable in bionic.
- // mNetd.setDnsNetworkForPid(netId, pid);
-// } catch (Exception e) {
-// Slog.e(TAG, "exception setting interface for pid: " + e);
-// }
-// }
- }
- flushVmDnsCache();
- }
- }
-
@Override
public int getRestoreDefaultNetworkDelay(int networkType) {
String restoreDefaultNetworkDelayStr = SystemProperties.get(
@@ -4829,6 +4285,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (defaultNai != null && defaultNai.network.netId == netId) {
setDefaultDnsSystemProperties(dnses);
}
+ flushVmDnsCache();
}
}
@@ -4924,6 +4381,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private void makeDefault(NetworkAgentInfo newNetwork) {
if (VDBG) log("Switching to new default network: " + newNetwork);
+ mActiveDefaultNetwork = newNetwork.networkInfo.getType();
setupDataActivityTracking(newNetwork);
try {
mNetd.setDefaultNetId(newNetwork.network.netId);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 40eb3e4..c16be50 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -20,13 +20,13 @@ import android.hardware.hdmi.HdmiCecDeviceInfo;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.SystemProperties;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -53,6 +53,9 @@ abstract class HdmiCecLocalDevice {
int logicalAddress;
int physicalAddress;
+ public ActiveSource() {
+ invalidate();
+ }
public ActiveSource(int logical, int physical) {
logicalAddress = logical;
physicalAddress = physical;
@@ -63,6 +66,10 @@ abstract class HdmiCecLocalDevice {
public boolean isValid() {
return HdmiUtils.isValidAddress(logicalAddress);
}
+ public void invalidate() {
+ logicalAddress = Constants.ADDR_INVALID;
+ physicalAddress = Constants.INVALID_PHYSICAL_ADDRESS;
+ }
public boolean equals(int logical, int physical) {
return logicalAddress == logical && physicalAddress == physical;
}
@@ -82,8 +89,7 @@ abstract class HdmiCecLocalDevice {
}
// Logical address of the active source.
@GuardedBy("mLock")
- protected final ActiveSource mActiveSource =
- new ActiveSource(-1, Constants.INVALID_PHYSICAL_ADDRESS);
+ protected final ActiveSource mActiveSource = new ActiveSource();
// Active routing path. Physical address of the active source but not all the time, such as
// when the new active source does not claim itself to be one. Note that we don't keep
@@ -505,9 +511,12 @@ abstract class HdmiCecLocalDevice {
@ServiceThreadOnly
<T extends FeatureAction> List<T> getActions(final Class<T> clazz) {
assertRunOnServiceThread();
- ArrayList<T> actions = new ArrayList<>();
+ List<T> actions = Collections.<T>emptyList();
for (FeatureAction action : mActions) {
if (action.getClass().equals(clazz)) {
+ if (actions.isEmpty()) {
+ actions = new ArrayList<T>();
+ }
actions.add((T) action);
}
}
@@ -552,7 +561,10 @@ abstract class HdmiCecLocalDevice {
protected void checkIfPendingActionsCleared() {
if (mActions.isEmpty() && mPendingActionClearedCallback != null) {
- mPendingActionClearedCallback.onCleared(this);
+ PendingActionClearedCallback callback = mPendingActionClearedCallback;
+ // To prevent from calling the callback again during handling the callback itself.
+ mPendingActionClearedCallback = null;
+ callback.onCleared(this);
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index f93d20f..9038fbc 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -234,10 +234,10 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
void updateActiveInput(int path, boolean notifyInputChange) {
assertRunOnServiceThread();
// Seq #15
- int portId = mService.pathToPortId(path);
- if (portId == getActivePortId()) {
+ if (path == getActivePath()) {
return;
}
+ int portId = mService.pathToPortId(path);
setActivePath(path);
setPrevPortId(portId);
// TODO: Handle PAP/PIP case.
@@ -265,7 +265,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
return;
}
- setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS);
+ mActiveSource.invalidate();
if (!mService.isControlEnabled()) {
setActivePortId(portId);
invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
@@ -480,9 +480,9 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
byte[] params = message.getParams();
int currentPath = HdmiUtils.twoBytesToInt(params);
if (HdmiUtils.isAffectingActiveRoutingPath(getActivePath(), currentPath)) {
- int newPath = HdmiUtils.twoBytesToInt(params, 2);
- setActivePath(newPath);
+ mActiveSource.invalidate();
removeAction(RoutingControlAction.class);
+ int newPath = HdmiUtils.twoBytesToInt(params, 2);
addAndStartAction(new RoutingControlAction(this, newPath, true, null));
}
return true;
@@ -1249,18 +1249,6 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
}
}
- @Override
- @ServiceThreadOnly
- protected boolean handleStandby(HdmiCecMessage message) {
- assertRunOnServiceThread();
- // Seq #12
- // Tv accepts directly addressed <Standby> only.
- if (message.getDestination() == mAddress) {
- super.handleStandby(message);
- }
- return false;
- }
-
boolean isProhibitMode() {
return mService.isProhibitMode();
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 2272283..390d121 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -200,10 +200,10 @@ public final class HdmiControlService extends SystemService {
private List<HdmiPortInfo> mPortInfo;
// Map from path(physical address) to port ID.
- private SparseIntArray mPortIdMap = new SparseIntArray();
+ private final SparseIntArray mPortIdMap = new SparseIntArray();
// Map from port ID to HdmiPortInfo.
- private SparseArray<HdmiPortInfo> mPortInfoMap = new SparseArray<>();
+ private final SparseArray<HdmiPortInfo> mPortInfoMap = new SparseArray<>();
private HdmiCecMessageValidator mMessageValidator;
@@ -1414,8 +1414,8 @@ public final class HdmiControlService extends SystemService {
Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType);
devices.remove(device);
if (devices.isEmpty()) {
- clearLocalDevices();
onStandbyCompleted();
+ clearLocalDevices();
}
}
});
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 587f596..9ac90dc 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -224,6 +224,9 @@ public class JobSchedulerService extends com.android.server.SystemService
}
private void cancelJobLocked(JobStatus cancelled) {
+ if (DEBUG) {
+ Slog.d(TAG, "Cancelling: " + cancelled);
+ }
// Remove from store.
stopTrackingJob(cancelled);
// Remove from pending queue.
@@ -447,8 +450,7 @@ public class JobSchedulerService extends com.android.server.SystemService
}
if (!stopTrackingJob(jobStatus)) {
if (DEBUG) {
- Slog.e(TAG, "Error removing job: could not find job to remove. Was job " +
- "removed while executing?");
+ Slog.d(TAG, "Could not find job to remove. Was job removed while executing?");
}
return;
}
@@ -611,7 +613,7 @@ public class JobSchedulerService extends com.android.server.SystemService
final JobStatus running = jsc.getRunningJob();
if (running != null && running.matches(nextPending.getUid(),
nextPending.getJobId())) {
- // Already running this tId for this uId, skip.
+ // Already running this job for this uId, skip.
availableContext = null;
break;
}
@@ -691,7 +693,7 @@ public class JobSchedulerService extends com.android.server.SystemService
@Override
public int schedule(JobInfo job) throws RemoteException {
if (DEBUG) {
- Slog.d(TAG, "Scheduling job: " + job);
+ Slog.d(TAG, "Scheduling job: " + job.toString());
}
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index ee45833..5297911 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -34,7 +34,6 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
-import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -45,8 +44,22 @@ import com.android.server.job.controllers.JobStatus;
import java.util.concurrent.atomic.AtomicBoolean;
/**
- * Handles client binding and lifecycle of a job. A job will only execute one at a time on an
- * instance of this class.
+ * Handles client binding and lifecycle of a job. Jobs execute one at a time on an instance of this
+ * class.
+ *
+ * There are two important interactions into this class from the
+ * {@link com.android.server.job.JobSchedulerService}. To execute a job and to cancel a job.
+ * - Execution of a new job is handled by the {@link #mAvailable}. This bit is flipped once when a
+ * job lands, and again when it is complete.
+ * - Cancelling is trickier, because there are also interactions from the client. It's possible
+ * the {@link com.android.server.job.JobServiceContext.JobServiceHandler} tries to process a
+ * {@link #MSG_CANCEL} after the client has already finished. This is handled by having
+ * {@link com.android.server.job.JobServiceContext.JobServiceHandler#handleCancelH} check whether
+ * the context is still valid.
+ * To mitigate this, tearing down the context removes all messages from the handler, including any
+ * tardy {@link #MSG_CANCEL}s. Additionally, we avoid sending duplicate onStopJob()
+ * calls to the client after they've specified jobFinished().
+ *
*/
public class JobServiceContext extends IJobCallback.Stub implements ServiceConnection {
private static final boolean DEBUG = true;
@@ -60,7 +73,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
private static final long OP_TIMEOUT_MILLIS = 8 * 1000;
private static final String[] VERB_STRINGS = {
- "VERB_STARTING", "VERB_EXECUTING", "VERB_STOPPING", "VERB_PENDING"
+ "VERB_BINDING", "VERB_STARTING", "VERB_EXECUTING", "VERB_STOPPING"
};
// States that a job occupies while interacting with the client.
@@ -101,7 +114,10 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
IJobService service;
private final Object mLock = new Object();
- /** Whether this context is free. */
+ /**
+ * Whether this context is free. This is set to false at the start of execution, and reset to
+ * true when execution is complete.
+ */
@GuardedBy("mLock")
private boolean mAvailable;
/** Track start time. */
@@ -164,9 +180,15 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
}
}
- /** Used externally to query the running job. Will return null if there is no job running. */
+ /**
+ * Used externally to query the running job. Will return null if there is no job running.
+ * Be careful when using this function, at any moment it's possible that the job returned may
+ * stop executing.
+ */
JobStatus getRunningJob() {
- return mRunningJob;
+ synchronized (mLock) {
+ return mRunningJob;
+ }
}
/** Called externally when a job that was scheduled for execution should be cancelled. */
@@ -242,10 +264,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
}
- /**
- * If the client service crashes we reschedule this job and clean up.
- * @param name The concrete component name of the service whose
- */
+ /** If the client service crashes we reschedule this job and clean up. */
@Override
public void onServiceDisconnected(ComponentName name) {
mCallbackHandler.obtainMessage(MSG_SHUTDOWN_EXECUTION).sendToTarget();
@@ -312,7 +331,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
closeAndCleanupJobH(true /* needsReschedule */);
break;
default:
- Log.e(TAG, "Unrecognised message: " + message);
+ Slog.e(TAG, "Unrecognised message: " + message);
}
}
@@ -337,7 +356,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
scheduleOpTimeOut();
service.startJob(mParams);
} catch (RemoteException e) {
- Log.e(TAG, "Error sending onStart message to '" +
+ Slog.e(TAG, "Error sending onStart message to '" +
mRunningJob.getServiceComponent().getShortClassName() + "' ", e);
}
}
@@ -359,6 +378,9 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
return;
}
if (mCancelled.get()) {
+ if (DEBUG) {
+ Slog.d(TAG, "Job cancelled while waiting for onStartJob to complete.");
+ }
// Cancelled *while* waiting for acknowledgeStartMessage from client.
handleCancelH();
return;
@@ -366,7 +388,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
scheduleOpTimeOut();
break;
default:
- Log.e(TAG, "Handling started job but job wasn't starting! Was "
+ Slog.e(TAG, "Handling started job but job wasn't starting! Was "
+ VERB_STRINGS[mVerb] + ".");
return;
}
@@ -396,16 +418,31 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
* {@link #onServiceConnected(android.content.ComponentName, android.os.IBinder)}
* _STARTING -> Mark as cancelled and wait for
* {@link JobServiceContext#acknowledgeStartMessage(int, boolean)}
- * _EXECUTING -> call {@link #sendStopMessageH}}.
+ * _EXECUTING -> call {@link #sendStopMessageH}}, but only if there are no callbacks
+ * in the message queue.
* _ENDING -> No point in doing anything here, so we ignore.
*/
private void handleCancelH() {
+ if (mRunningJob == null) {
+ if (DEBUG) {
+ Slog.d(TAG, "Trying to process cancel for torn-down context, ignoring.");
+ }
+ return;
+ }
+ if (JobSchedulerService.DEBUG) {
+ Slog.d(TAG, "Handling cancel for: " + mRunningJob.getJobId() + " "
+ + VERB_STRINGS[mVerb]);
+ }
switch (mVerb) {
case VERB_BINDING:
case VERB_STARTING:
mCancelled.set(true);
break;
case VERB_EXECUTING:
+ if (hasMessages(MSG_CALLBACK)) {
+ // If the client has called jobFinished, ignore this cancel.
+ return;
+ }
sendStopMessageH();
break;
case VERB_STOPPING:
@@ -419,8 +456,8 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
/** Process MSG_TIMEOUT here. */
private void handleOpTimeoutH() {
- if (Log.isLoggable(JobSchedulerService.TAG, Log.DEBUG)) {
- Log.d(TAG, "MSG_TIMEOUT of " +
+ if (JobSchedulerService.DEBUG) {
+ Slog.d(TAG, "MSG_TIMEOUT of " +
mRunningJob.getServiceComponent().getShortClassName() + " : "
+ mParams.getJobId());
}
@@ -431,28 +468,28 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
// Client unresponsive - wedged or failed to respond in time. We don't really
// know what happened so let's log it and notify the JobScheduler
// FINISHED/NO-RETRY.
- Log.e(TAG, "No response from client for onStartJob '" +
- mRunningJob.getServiceComponent().getShortClassName() + "' tId: "
+ Slog.e(TAG, "No response from client for onStartJob '" +
+ mRunningJob.getServiceComponent().getShortClassName() + "' jId: "
+ jobId);
closeAndCleanupJobH(false /* needsReschedule */);
break;
case VERB_STOPPING:
// At least we got somewhere, so fail but ask the JobScheduler to reschedule.
- Log.e(TAG, "No response from client for onStopJob, '" +
- mRunningJob.getServiceComponent().getShortClassName() + "' tId: "
+ Slog.e(TAG, "No response from client for onStopJob, '" +
+ mRunningJob.getServiceComponent().getShortClassName() + "' jId: "
+ jobId);
closeAndCleanupJobH(true /* needsReschedule */);
break;
case VERB_EXECUTING:
// Not an error - client ran out of time.
- Log.i(TAG, "Client timed out while executing (no jobFinished received)." +
+ Slog.i(TAG, "Client timed out while executing (no jobFinished received)." +
" sending onStop. " +
- mRunningJob.getServiceComponent().getShortClassName() + "' tId: "
+ mRunningJob.getServiceComponent().getShortClassName() + "' jId: "
+ jobId);
sendStopMessageH();
break;
default:
- Log.e(TAG, "Handling timeout for an unknown active job state: "
+ Slog.e(TAG, "Handling timeout for an unknown active job state: "
+ mRunningJob);
return;
}
@@ -465,7 +502,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
private void sendStopMessageH() {
mCallbackHandler.removeMessages(MSG_TIMEOUT);
if (mVerb != VERB_EXECUTING) {
- Log.e(TAG, "Sending onStopJob for a job that isn't started. " + mRunningJob);
+ Slog.e(TAG, "Sending onStopJob for a job that isn't started. " + mRunningJob);
closeAndCleanupJobH(false /* reschedule */);
return;
}
@@ -474,7 +511,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
scheduleOpTimeOut();
service.stopJob(mParams);
} catch (RemoteException e) {
- Log.e(TAG, "Error sending onStopJob to client.", e);
+ Slog.e(TAG, "Error sending onStopJob to client.", e);
closeAndCleanupJobH(false /* reschedule */);
}
}
@@ -486,8 +523,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
* we want to clean up internally.
*/
private void closeAndCleanupJobH(boolean reschedule) {
- removeMessages(MSG_TIMEOUT);
- mCompletedListener.onJobCompleted(mRunningJob, reschedule);
+ final JobStatus completedJob = mRunningJob;
synchronized (mLock) {
try {
mBatteryStats.noteJobFinish(mRunningJob.getName(), mRunningJob.getUid());
@@ -504,12 +540,18 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
service = null;
mAvailable = true;
}
+ removeMessages(MSG_TIMEOUT);
+ removeMessages(MSG_CALLBACK);
+ removeMessages(MSG_SERVICE_BOUND);
+ removeMessages(MSG_CANCEL);
+ removeMessages(MSG_SHUTDOWN_EXECUTION);
+ mCompletedListener.onJobCompleted(completedJob, reschedule);
}
/**
- * Called when sending a message to the client, over whose execution we have no control. If we
- * haven't received a response in a certain amount of time, we want to give up and carry on
- * with life.
+ * Called when sending a message to the client, over whose execution we have no control. If
+ * we haven't received a response in a certain amount of time, we want to give up and carry
+ * on with life.
*/
private void scheduleOpTimeOut() {
mCallbackHandler.removeMessages(MSG_TIMEOUT);
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 65e617b..077d16f 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -20,6 +20,7 @@ import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED;
import static android.media.tv.TvInputManager.INPUT_STATE_DISCONNECTED;
import android.content.Context;
+import android.content.Intent;
import android.hardware.hdmi.HdmiCecDeviceInfo;
import android.hardware.hdmi.HdmiHotplugEvent;
import android.hardware.hdmi.IHdmiControlService;
@@ -34,6 +35,7 @@ import android.media.AudioPortConfig;
import android.media.tv.ITvInputHardware;
import android.media.tv.ITvInputHardwareCallback;
import android.media.tv.TvInputHardwareInfo;
+import android.media.tv.TvContract;
import android.media.tv.TvInputInfo;
import android.media.tv.TvStreamConfig;
import android.os.Handler;
@@ -759,8 +761,21 @@ class TvInputHardwareManager implements TvInputHal.Callback {
private final class HdmiInputChangeListener extends IHdmiInputChangeListener.Stub {
@Override
public void onChanged(HdmiCecDeviceInfo device) throws RemoteException {
- // TODO: Build a channel Uri for the TvInputInfo associated with the logical device
- // and send an intent to TV app
+ String inputId;
+ synchronized (mLock) {
+ if (device.isCecDevice()) {
+ inputId = mHdmiCecInputIdMap.get(device.getLogicalAddress());
+ } else {
+ inputId = findInputIdForHdmiPortLocked(device.getPortId());
+ }
+ }
+ if (inputId != null) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(TvContract.buildChannelUriForPassthroughTvInput(inputId));
+ mContext.startActivity(intent);
+ } else {
+ Slog.w(TAG, "onChanged: InputId cannot be found for :" + device);
+ }
}
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
index 1e4a518..fe1b92a 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
@@ -19,6 +19,8 @@ package com.android.server.voiceinteraction;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.Keyphrase;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
@@ -40,8 +42,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
static final String TAG = "SoundTriggerHelper";
// TODO: Set to false.
static final boolean DBG = true;
- // TODO: Remove this.
- static final int TEMP_KEYPHRASE_ID = 100;
/**
* Return codes for {@link #startRecognition(int, KeyphraseSoundModel,
@@ -117,7 +117,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
if (mCurrentSoundModelHandle != INVALID_SOUND_MODEL_HANDLE) {
- Slog.w(TAG, "Canceling previous recognition");
+ Slog.w(TAG, "Unloading previous sound model");
// TODO: Inspect the return codes here.
mModule.unloadSoundModel(mCurrentSoundModelHandle);
mCurrentSoundModelHandle = INVALID_SOUND_MODEL_HANDLE;
@@ -127,6 +127,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
// Notify them that it was stopped.
IRecognitionStatusCallback oldListener = mActiveListeners.get(keyphraseId);
if (oldListener != null && oldListener.asBinder() != listener.asBinder()) {
+ Slog.w(TAG, "Canceling previous recognition");
try {
oldListener.onDetectionStopped();
} catch (RemoteException e) {
@@ -221,33 +222,51 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
//---- SoundTrigger.StatusListener methods
@Override
public void onRecognition(RecognitionEvent event) {
- // Check which keyphrase triggered, and fire the appropriate event.
- // TODO: Get the keyphrase out of the event and fire events on it.
- // For now, as a nasty workaround, we fire all events to the listener for
- // keyphrase with TEMP_KEYPHRASE_ID.
- IRecognitionStatusCallback listener = null;
- synchronized(this) {
- // TODO: The keyphrase should come from the recognition event
- // as it may be for a different keyphrase than the current one.
- listener = mActiveListeners.get(TEMP_KEYPHRASE_ID);
- }
- if (listener == null) {
- Slog.w(TAG, "received onRecognition event without any listener for it");
+ if (event == null) {
+ Slog.w(TAG, "Invalid recognition event!");
return;
}
+ if (DBG) Slog.d(TAG, "onRecognition: " + event);
switch (event.status) {
- case SoundTrigger.RECOGNITION_STATUS_SUCCESS:
+ // Fire aborts/failures to all listeners since it's not tied to a keyphrase.
+ case SoundTrigger.RECOGNITION_STATUS_ABORT: // fall-through
+ case SoundTrigger.RECOGNITION_STATUS_FAILURE:
try {
- listener.onDetected(event);
+ synchronized (this) {
+ for (int i = 0; i < mActiveListeners.size(); i++) {
+ mActiveListeners.valueAt(i).onDetectionStopped();
+ }
+ }
} catch (RemoteException e) {
- Slog.w(TAG, "RemoteException in onDetected");
+ Slog.w(TAG, "RemoteException in onDetectionStopped");
}
break;
- case SoundTrigger.RECOGNITION_STATUS_ABORT: // fall-through
- case SoundTrigger.RECOGNITION_STATUS_FAILURE:
+ case SoundTrigger.RECOGNITION_STATUS_SUCCESS:
+ if (!(event instanceof KeyphraseRecognitionEvent)) {
+ Slog.w(TAG, "Invalid recognition event!");
+ return;
+ }
+
+ KeyphraseRecognitionExtra[] keyphraseExtras =
+ ((KeyphraseRecognitionEvent) event).keyphraseExtras;
+ if (keyphraseExtras == null || keyphraseExtras.length == 0) {
+ Slog.w(TAG, "Invalid keyphrase recognition event!");
+ return;
+ }
+ // TODO: Handle more than one keyphrase extras.
+ int keyphraseId = keyphraseExtras[0].id;
try {
- listener.onDetectionStopped();
+ synchronized(this) {
+ // Check which keyphrase triggered, and fire the appropriate event.
+ IRecognitionStatusCallback listener = mActiveListeners.get(keyphraseId);
+ if (listener != null) {
+ listener.onDetected((KeyphraseRecognitionEvent) event);
+ } else {
+ Slog.w(TAG, "received onRecognition event without any listener for it");
+ return;
+ }
+ }
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException in onDetectionStopped");
}
@@ -257,6 +276,17 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
@Override
public void onServiceDied() {
- // TODO: Figure out how to restart the recognition here.
+ synchronized (this) {
+ try {
+ for (int i = 0; i < mActiveListeners.size(); i++) {
+ mActiveListeners.valueAt(i).onDetectionStopped();
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException in onDetectionStopped");
+ }
+ mCurrentSoundModelHandle = INVALID_SOUND_MODEL_HANDLE;
+ // Remove all listeners.
+ mActiveListeners.clear();
+ }
}
}
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index 7123e09..8845821 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -130,10 +130,10 @@ public abstract class Connection {
/**
* Returns the video state of the call.
- * Valid values: {@link android.telecomm.VideoCallProfile#VIDEO_STATE_AUDIO_ONLY},
- * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_BIDIRECTIONAL},
- * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_TX_ENABLED},
- * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_RX_ENABLED}.
+ * Valid values: {@link android.telecomm.VideoCallProfile.VideoState#AUDIO_ONLY},
+ * {@link android.telecomm.VideoCallProfile.VideoState#BIDIRECTIONAL},
+ * {@link android.telecomm.VideoCallProfile.VideoState#TX_ENABLED},
+ * {@link android.telecomm.VideoCallProfile.VideoState#RX_ENABLED}.
*
* @return The video state of the call.
*/
@@ -357,10 +357,10 @@ public abstract class Connection {
/**
* Set the video state for the connection.
- * Valid values: {@link android.telecomm.VideoCallProfile#VIDEO_STATE_AUDIO_ONLY},
- * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_BIDIRECTIONAL},
- * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_TX_ENABLED},
- * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_RX_ENABLED}.
+ * Valid values: {@link android.telecomm.VideoCallProfile.VideoState#AUDIO_ONLY},
+ * {@link android.telecomm.VideoCallProfile.VideoState#BIDIRECTIONAL},
+ * {@link android.telecomm.VideoCallProfile.VideoState#TX_ENABLED},
+ * {@link android.telecomm.VideoCallProfile.VideoState#RX_ENABLED}.
*
* @param videoState The new video state.
*/
diff --git a/telecomm/java/android/telecomm/ConnectionRequest.java b/telecomm/java/android/telecomm/ConnectionRequest.java
index 020b692..1016091 100644
--- a/telecomm/java/android/telecomm/ConnectionRequest.java
+++ b/telecomm/java/android/telecomm/ConnectionRequest.java
@@ -101,10 +101,10 @@ public final class ConnectionRequest implements Parcelable {
/**
* Determines the video state for the connection.
- * Valid values: {@link VideoCallProfile#VIDEO_STATE_AUDIO_ONLY},
- * {@link VideoCallProfile#VIDEO_STATE_BIDIRECTIONAL},
- * {@link VideoCallProfile#VIDEO_STATE_TX_ENABLED},
- * {@link VideoCallProfile#VIDEO_STATE_RX_ENABLED}.
+ * Valid values: {@link VideoCallProfile.VideoState#AUDIO_ONLY},
+ * {@link VideoCallProfile.VideoState#BIDIRECTIONAL},
+ * {@link VideoCallProfile.VideoState#TX_ENABLED},
+ * {@link VideoCallProfile.VideoState#RX_ENABLED}.
*
* @return The video state for the connection.
*/
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index fb719a3..1484021 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -121,9 +121,15 @@ public abstract class ConnectionService extends Service {
}
@Override
- public void createConnection(ConnectionRequest request, boolean isIncoming) {
- mHandler.obtainMessage(
- MSG_CREATE_CONNECTION, isIncoming ? 1 : 0, 0, request).sendToTarget();
+ public void createConnection(
+ PhoneAccountHandle connectionManagerPhoneAccount,
+ ConnectionRequest request,
+ boolean isIncoming) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = connectionManagerPhoneAccount;
+ args.arg2 = request;
+ args.argi1 = isIncoming ? 1 : 0;
+ mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
}
@Override
@@ -217,9 +223,19 @@ public abstract class ConnectionService extends Service {
mAdapter.addAdapter((IConnectionServiceAdapter) msg.obj);
onAdapterAttached();
break;
- case MSG_CREATE_CONNECTION:
- createConnection((ConnectionRequest) msg.obj, msg.arg1 == 1);
+ case MSG_CREATE_CONNECTION: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ PhoneAccountHandle connectionManagerPhoneAccount =
+ (PhoneAccountHandle) args.arg1;
+ ConnectionRequest request = (ConnectionRequest) args.arg2;
+ boolean isIncoming = args.argi1 == 1;
+ createConnection(connectionManagerPhoneAccount, request, isIncoming);
+ } finally {
+ args.recycle();
+ }
break;
+ }
case MSG_ABORT:
abort((String) msg.obj);
break;
@@ -428,14 +444,17 @@ public abstract class ConnectionService extends Service {
* incoming call. In either case, telecomm will cycle through a set of services and call
* createConnection util a connection service cancels the process or completes it successfully.
*/
- private void createConnection(final ConnectionRequest request, boolean isIncoming) {
+ private void createConnection(
+ final PhoneAccountHandle callManagerAccount,
+ final ConnectionRequest request,
+ boolean isIncoming) {
Log.d(this, "call %s", request);
final Connection createdConnection;
if (isIncoming) {
- createdConnection = onCreateIncomingConnection(request);
+ createdConnection = onCreateIncomingConnection(callManagerAccount, request);
} else {
- createdConnection = onCreateOutgoingConnection(request);
+ createdConnection = onCreateOutgoingConnection(callManagerAccount, request);
}
if (createdConnection != null) {
@@ -641,40 +660,94 @@ public abstract class ConnectionService extends Service {
});
}
- public final RemoteConnection createRemoteIncomingConnection(ConnectionRequest request) {
- return mRemoteConnectionManager.createRemoteConnection(request, true);
+ /**
+ * Ask some other {@code ConnectionService} to create a {@code RemoteConnection} given an
+ * incoming request. This is used to attach to existing incoming calls.
+ *
+ * @param connectionManagerPhoneAccount See description at
+ * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
+ * @param request Details about the incoming call.
+ * @return The {@code Connection} object to satisfy this call, or {@code null} to
+ * not handle the call.
+ */
+ public final RemoteConnection createRemoteIncomingConnection(
+ PhoneAccountHandle connectionManagerPhoneAccount,
+ ConnectionRequest request) {
+ return mRemoteConnectionManager.createRemoteConnection(
+ connectionManagerPhoneAccount, request, true);
}
- public final RemoteConnection createRemoteOutgoingConnection(ConnectionRequest request) {
- return mRemoteConnectionManager.createRemoteConnection(request, false);
+ /**
+ * Ask some other {@code ConnectionService} to create a {@code RemoteConnection} given an
+ * outgoing request. This is used to initiate new outgoing calls.
+ *
+ * @param connectionManagerPhoneAccount See description at
+ * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
+ * @param request Details about the incoming call.
+ * @return The {@code Connection} object to satisfy this call, or {@code null} to
+ * not handle the call.
+ */
+ public final RemoteConnection createRemoteOutgoingConnection(
+ PhoneAccountHandle connectionManagerPhoneAccount,
+ ConnectionRequest request) {
+ return mRemoteConnectionManager.createRemoteConnection(
+ connectionManagerPhoneAccount, request, false);
}
/**
- * Returns all connections currently associated with this connection service.
+ * Returns all the active {@code Connection}s for which this {@code ConnectionService}
+ * has taken responsibility.
+ *
+ * @return A collection of {@code Connection}s created by this {@code ConnectionService}.
*/
public final Collection<Connection> getAllConnections() {
return mConnectionById.values();
}
/**
- * Create a Connection given an incoming request. This is used to attach to existing incoming
- * calls.
- * @param request Details about the incoming call.
+ * Create a {@code Connection} given an incoming request. This is used to attach to existing
+ * incoming calls.
*
- * @return The {@link Connection} object to satisfy this call, or {@code null} to not handle
- * the call.
+ * @param connectionManagerPhoneAccount See description at
+ * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
+ * @param request Details about the incoming call.
+ * @return The {@code Connection} object to satisfy this call, or {@code null} to
+ * not handle the call.
*/
- public Connection onCreateIncomingConnection(ConnectionRequest request) { return null; }
+ public Connection onCreateIncomingConnection(
+ PhoneAccountHandle connectionManagerPhoneAccount,
+ ConnectionRequest request) {
+ return null;
+ }
/**
- * Create a Connection given an outgoing request. This is used to initiate new outgoing calls.
- * @param request Details about the outgoing call.
- *
- * @return The {@link Connection} object to satisfy this request,
- * or null to not handle the call.
+ * Create a {@code Connection} given an outgoing request. This is used to initiate new
+ * outgoing calls.
*
+ * @param connectionManagerPhoneAccount The connection manager account to use for managing
+ * this call.
+ * <p>
+ * If this parameter is not {@code null}, it means that this {@code ConnectionService}
+ * has registered one or more {@code PhoneAccount}s having
+ * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}. This parameter will contain
+ * one of these {@code PhoneAccount}s, while the {@code request} will contain another
+ * (usually but not always distinct) {@code PhoneAccount} to be used for actually
+ * making the connection.
+ * <p>
+ * If this parameter is {@code null}, it means that this {@code ConnectionService} is
+ * being asked to make a direct connection. The
+ * {@link ConnectionRequest#getAccountHandle()} of parameter {@code request} will be
+ * a {@code PhoneAccount} registered by this {@code ConnectionService} to use for
+ * making the connection.
+ * @param request Details about the outgoing call.
+ * @return The {@code Connection} object to satisfy this call, or the result of an invocation
+ * of {@link Connection#getFailedConnection(int, String)} to not handle the call.
*/
- public Connection onCreateOutgoingConnection(ConnectionRequest request) { return null; }
+ public Connection onCreateOutgoingConnection(
+ PhoneAccountHandle connectionManagerPhoneAccount,
+ ConnectionRequest request) {
+ return null;
+ }
/**
* Returns a new or existing conference connection when the the user elects to convert the
diff --git a/telecomm/java/android/telecomm/InCallAdapter.java b/telecomm/java/android/telecomm/InCallAdapter.java
index 816c456..964686a 100644
--- a/telecomm/java/android/telecomm/InCallAdapter.java
+++ b/telecomm/java/android/telecomm/InCallAdapter.java
@@ -252,4 +252,28 @@ public final class InCallAdapter {
} catch (RemoteException ignored) {
}
}
+
+ /**
+ * Instructs Telecomm to turn the proximity sensor on.
+ */
+ public void turnProximitySensorOn() {
+ try {
+ mAdapter.turnOnProximitySensor();
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ /**
+ * Instructs Telecomm to turn the proximity sensor off.
+ *
+ * @param screenOnImmediately If true, the screen will be turned on immediately if it was
+ * previously off. Otherwise, the screen will only be turned on after the proximity sensor
+ * is no longer triggered.
+ */
+ public void turnProximitySensorOff(boolean screenOnImmediately) {
+ try {
+ mAdapter.turnOffProximitySensor(screenOnImmediately);
+ } catch (RemoteException ignored) {
+ }
+ }
}
diff --git a/telecomm/java/android/telecomm/Phone.java b/telecomm/java/android/telecomm/Phone.java
index ce95acf..b4c8a80 100644
--- a/telecomm/java/android/telecomm/Phone.java
+++ b/telecomm/java/android/telecomm/Phone.java
@@ -210,6 +210,29 @@ public final class Phone {
}
/**
+ * Turns the proximity sensor on. When this request is made, the proximity sensor will
+ * become active, and the touch screen and display will be turned off when the user's face
+ * is detected to be in close proximity to the screen. This operation is a no-op on devices
+ * that do not have a proximity sensor.
+ */
+ public final void setProximitySensorOn() {
+ mInCallAdapter.turnProximitySensorOn();
+ }
+
+ /**
+ * Turns the proximity sensor off. When this request is made, the proximity sensor will
+ * become inactive, and no longer affect the touch screen and display. This operation is a
+ * no-op on devices that do not have a proximity sensor.
+ *
+ * @param screenOnImmediately If true, the screen will be turned on immediately if it was
+ * previously off. Otherwise, the screen will only be turned on after the proximity sensor
+ * is no longer triggered.
+ */
+ public final void setProximitySensorOff(boolean screenOnImmediately) {
+ mInCallAdapter.turnProximitySensorOff(screenOnImmediately);
+ }
+
+ /**
* Obtains the current phone call audio state of the {@code Phone}.
*
* @return An object encapsulating the audio state.
diff --git a/telecomm/java/android/telecomm/PhoneAccount.java b/telecomm/java/android/telecomm/PhoneAccount.java
index 1f9071e..0fea7ba 100644
--- a/telecomm/java/android/telecomm/PhoneAccount.java
+++ b/telecomm/java/android/telecomm/PhoneAccount.java
@@ -32,24 +32,24 @@ import java.util.MissingResourceException;
public class PhoneAccount implements Parcelable {
/**
- * Flag indicating that this {@code PhoneAccount} can act as a call manager for
- * traditional SIM-based telephony calls. The {@link ConnectionService} associated with this
- * phone-account will be allowed to manage SIM-based phone calls including using its own
- * proprietary phone-call implementation (like VoIP calling) to make calls instead of the
- * telephony stack.
+ * Flag indicating that this {@code PhoneAccount} can act as a connection manager for
+ * other connections. The {@link ConnectionService} associated with this {@code PhoneAccount}
+ * will be allowed to manage phone calls including using its own proprietary phone-call
+ * implementation (like VoIP calling) to make calls instead of the telephony stack.
+ * <p>
* When a user opts to place a call using the SIM-based telephony stack, the connection-service
* associated with this phone-account will be attempted first if the user has explicitly
- * selected it to be used as the default call-manager.
+ * selected it to be used as the default connection manager.
* <p>
* See {@link #getCapabilities}
*/
- public static final int CAPABILITY_SIM_CALL_MANAGER = 0x1;
+ public static final int CAPABILITY_CONNECTION_MANAGER = 0x1;
/**
* Flag indicating that this {@code PhoneAccount} can make phone calls in place of
* traditional SIM-based telephony calls. This account will be treated as a distinct method
* for placing calls alongside the traditional SIM-based telephony stack. This flag is
- * distinct from {@link #CAPABILITY_SIM_CALL_MANAGER} in that it is not allowed to manage
+ * distinct from {@link #CAPABILITY_CONNECTION_MANAGER} in that it is not allowed to manage
* calls from or use the built-in telephony stack to place its calls.
* <p>
* See {@link #getCapabilities}
@@ -66,6 +66,11 @@ public class PhoneAccount implements Parcelable {
*/
public static final int CAPABILITY_SIM_SUBSCRIPTION = 0x4;
+ /**
+ * Flag indicating that this {@code PhoneAccount} is capable of video calling.
+ */
+ public static final int CAPABILITY_VIDEO_CALLING = 0x8;
+
private final PhoneAccountHandle mAccountHandle;
private final Uri mHandle;
private final String mSubscriptionNumber;
@@ -73,7 +78,6 @@ public class PhoneAccount implements Parcelable {
private final int mIconResId;
private final CharSequence mLabel;
private final CharSequence mShortDescription;
- private boolean mVideoCallingSupported;
public PhoneAccount(
PhoneAccountHandle account,
@@ -82,8 +86,7 @@ public class PhoneAccount implements Parcelable {
int capabilities,
int iconResId,
CharSequence label,
- CharSequence shortDescription,
- boolean supportsVideoCalling) {
+ CharSequence shortDescription) {
mAccountHandle = account;
mHandle = handle;
mSubscriptionNumber = subscriptionNumber;
@@ -91,7 +94,6 @@ public class PhoneAccount implements Parcelable {
mIconResId = iconResId;
mLabel = label;
mShortDescription = shortDescription;
- mVideoCallingSupported = supportsVideoCalling;
}
/**
@@ -189,15 +191,6 @@ public class PhoneAccount implements Parcelable {
}
}
- /**
- * Determines whether this {@code PhoneAccount} supports video calling.
- *
- * @return {@code true} if this {@code PhoneAccount} supports video calling.
- */
- public boolean isVideoCallingSupported() {
- return mVideoCallingSupported;
- }
-
//
// Parcelable implementation
//
@@ -216,7 +209,6 @@ public class PhoneAccount implements Parcelable {
out.writeInt(mIconResId);
out.writeCharSequence(mLabel);
out.writeCharSequence(mShortDescription);
- out.writeInt(mVideoCallingSupported ? 1 : 0);
}
public static final Creator<PhoneAccount> CREATOR
@@ -240,6 +232,5 @@ public class PhoneAccount implements Parcelable {
mIconResId = in.readInt();
mLabel = in.readCharSequence();
mShortDescription = in.readCharSequence();
- mVideoCallingSupported = in.readInt() == 1;
}
}
diff --git a/telecomm/java/android/telecomm/RemoteConnectionManager.java b/telecomm/java/android/telecomm/RemoteConnectionManager.java
index 3ca68a2..ce8bfbd 100644
--- a/telecomm/java/android/telecomm/RemoteConnectionManager.java
+++ b/telecomm/java/android/telecomm/RemoteConnectionManager.java
@@ -50,6 +50,7 @@ public class RemoteConnectionManager {
}
public RemoteConnection createRemoteConnection(
+ PhoneAccountHandle connectionManagerPhoneAccount,
ConnectionRequest request,
boolean isIncoming) {
PhoneAccountHandle accountHandle = request.getAccountHandle();
@@ -65,7 +66,8 @@ public class RemoteConnectionManager {
RemoteConnectionService remoteService = mRemoteConnectionServices.get(componentName);
if (remoteService != null) {
- return remoteService.createRemoteConnection(request, isIncoming);
+ return remoteService.createRemoteConnection(
+ connectionManagerPhoneAccount, request, isIncoming);
}
return null;
}
diff --git a/telecomm/java/android/telecomm/RemoteConnectionService.java b/telecomm/java/android/telecomm/RemoteConnectionService.java
index e6f47d2..501e843 100644
--- a/telecomm/java/android/telecomm/RemoteConnectionService.java
+++ b/telecomm/java/android/telecomm/RemoteConnectionService.java
@@ -32,8 +32,6 @@ import com.android.internal.telecomm.IConnectionServiceAdapter;
import com.android.internal.telecomm.IVideoCallProvider;
import com.android.internal.telecomm.RemoteServiceCallback;
-import java.util.LinkedList;
-import java.util.List;
import java.util.UUID;
/**
@@ -421,7 +419,10 @@ final class RemoteConnectionService implements DeathRecipient {
release();
}
- final RemoteConnection createRemoteConnection(ConnectionRequest request, boolean isIncoming) {
+ final RemoteConnection createRemoteConnection(
+ PhoneAccountHandle connectionManagerPhoneAccount,
+ ConnectionRequest request,
+ boolean isIncoming) {
if (mConnectionId == null) {
String id = UUID.randomUUID().toString();
ConnectionRequest newRequest = new ConnectionRequest(
@@ -433,7 +434,10 @@ final class RemoteConnectionService implements DeathRecipient {
request.getVideoState());
mConnection = new RemoteConnection(mConnectionService, request, isIncoming);
try {
- mConnectionService.createConnection(newRequest, isIncoming);
+ mConnectionService.createConnection(
+ connectionManagerPhoneAccount,
+ newRequest,
+ isIncoming);
mConnectionId = id;
} catch (RemoteException e) {
mConnection = RemoteConnection.failure(DisconnectCause.ERROR_UNSPECIFIED,
diff --git a/telecomm/java/android/telecomm/TelecommManager.java b/telecomm/java/android/telecomm/TelecommManager.java
index 49f95a6..0f31c52 100644
--- a/telecomm/java/android/telecomm/TelecommManager.java
+++ b/telecomm/java/android/telecomm/TelecommManager.java
@@ -72,10 +72,10 @@ public class TelecommManager {
* Optional extra for {@link android.content.Intent#ACTION_CALL} containing an integer that
* determines the desired video state for an outgoing call.
* Valid options:
- * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_AUDIO_ONLY},
- * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_BIDIRECTIONAL},
- * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_RX_ENABLED},
- * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_TX_ENABLED}.
+ * {@link android.telecomm.VideoCallProfile.VideoState#AUDIO_ONLY},
+ * {@link android.telecomm.VideoCallProfile.VideoState#BIDIRECTIONAL},
+ * {@link android.telecomm.VideoCallProfile.VideoState#RX_ENABLED},
+ * {@link android.telecomm.VideoCallProfile.VideoState#TX_ENABLED}.
*/
public static final String EXTRA_START_CALL_WITH_VIDEO_STATE =
"android.intent.extra.START_CALL_WITH_VIDEO_STATE";
diff --git a/telecomm/java/android/telecomm/VideoCallProfile.java b/telecomm/java/android/telecomm/VideoCallProfile.java
index 5b15e4a..24c6996 100644
--- a/telecomm/java/android/telecomm/VideoCallProfile.java
+++ b/telecomm/java/android/telecomm/VideoCallProfile.java
@@ -24,32 +24,6 @@ import android.os.Parcelable;
*/
public class VideoCallProfile implements Parcelable {
/**
- * Call is currently in an audio-only mode with no video transmission or receipt.
- */
- public static final int VIDEO_STATE_AUDIO_ONLY = 0x0;
-
- /**
- * Video transmission is enabled.
- */
- public static final int VIDEO_STATE_TX_ENABLED = 0x1;
-
- /**
- * Video reception is enabled.
- */
- public static final int VIDEO_STATE_RX_ENABLED = 0x2;
-
- /**
- * Video signal is bi-directional.
- */
- public static final int VIDEO_STATE_BIDIRECTIONAL =
- VIDEO_STATE_TX_ENABLED | VIDEO_STATE_RX_ENABLED;
-
- /**
- * Video is paused.
- */
- public static final int VIDEO_STATE_PAUSED = 0x4;
-
- /**
* "High" video quality.
*/
public static final int QUALITY_HIGH = 1;
@@ -94,13 +68,12 @@ public class VideoCallProfile implements Parcelable {
}
/**
- * The video state of the call. Stored as a bit-field describing whether video transmission and
- * receipt it enabled, as well as whether the video is currently muted.
- * Valid values: {@link VideoCallProfile#VIDEO_STATE_AUDIO_ONLY},
- * {@link VideoCallProfile#VIDEO_STATE_BIDIRECTIONAL},
- * {@link VideoCallProfile#VIDEO_STATE_TX_ENABLED},
- * {@link VideoCallProfile#VIDEO_STATE_RX_ENABLED},
- * {@link VideoCallProfile#VIDEO_STATE_PAUSED}.
+ * The video state of the call.
+ * Valid values: {@link VideoCallProfile.VideoState#AUDIO_ONLY},
+ * {@link VideoCallProfile.VideoState#BIDIRECTIONAL},
+ * {@link VideoCallProfile.VideoState#TX_ENABLED},
+ * {@link VideoCallProfile.VideoState#RX_ENABLED},
+ * {@link VideoCallProfile.VideoState#PAUSED}.
*/
public int getVideoState() {
return mVideoState;
@@ -165,4 +138,92 @@ public class VideoCallProfile implements Parcelable {
dest.writeInt(mVideoState);
dest.writeInt(mQuality);
}
+
+ /**
+ * The video state of the call, stored as a bit-field describing whether video transmission and
+ * receipt it enabled, as well as whether the video is currently muted.
+ */
+ public static class VideoState {
+ /**
+ * Call is currently in an audio-only mode with no video transmission or receipt.
+ */
+ public static final int AUDIO_ONLY = 0x0;
+
+ /**
+ * Video transmission is enabled.
+ */
+ public static final int TX_ENABLED = 0x1;
+
+ /**
+ * Video reception is enabled.
+ */
+ public static final int RX_ENABLED = 0x2;
+
+ /**
+ * Video signal is bi-directional.
+ */
+ public static final int BIDIRECTIONAL = TX_ENABLED | RX_ENABLED;
+
+ /**
+ * Video is paused.
+ */
+ public static final int PAUSED = 0x4;
+
+ /**
+ * Whether the video state is audio only.
+ * @param videoState The video state.
+ * @return Returns true if the video state is audio only.
+ */
+ public static boolean isAudioOnly(int videoState) {
+ return !hasState(videoState, TX_ENABLED) && !hasState(videoState, RX_ENABLED);
+ }
+
+ /**
+ * Whether the video transmission is enabled.
+ * @param videoState The video state.
+ * @return Returns true if the video transmission is enabled.
+ */
+ public static boolean isTransmissionEnabled(int videoState) {
+ return hasState(videoState, TX_ENABLED);
+ }
+
+ /**
+ * Whether the video reception is enabled.
+ * @param videoState The video state.
+ * @return Returns true if the video transmission is enabled.
+ */
+ public static boolean isReceptionEnabled(int videoState) {
+ return hasState(videoState, RX_ENABLED);
+ }
+
+ /**
+ * Whether the video signal is bi-directional.
+ * @param videoState
+ * @return Returns true if the video signal is bi-directional.
+ */
+ public static boolean isBidirectional(int videoState) {
+ return hasState(videoState, BIDIRECTIONAL);
+ }
+
+ /**
+ * Whether the video is paused.
+ * @param videoState The video state.
+ * @return Returns true if the video is paused.
+ */
+ public static boolean isPaused(int videoState) {
+ return hasState(videoState, PAUSED);
+ }
+
+ /**
+ * Determines if a specified state is set in a videoState bit-mask.
+ *
+ * @param videoState The video state bit-mask.
+ * @param state The state to check.
+ * @return {@code True} if the state is set.
+ * {@hide}
+ */
+ private static boolean hasState(int videoState, int state) {
+ return (videoState & state) == state;
+ }
+ }
}
diff --git a/telecomm/java/com/android/internal/telecomm/IConnectionService.aidl b/telecomm/java/com/android/internal/telecomm/IConnectionService.aidl
index 05375c9..4b05fb9 100644
--- a/telecomm/java/com/android/internal/telecomm/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/IConnectionService.aidl
@@ -19,6 +19,7 @@ package com.android.internal.telecomm;
import android.os.Bundle;
import android.telecomm.CallAudioState;
import android.telecomm.ConnectionRequest;
+import android.telecomm.PhoneAccountHandle;
import com.android.internal.telecomm.IConnectionServiceAdapter;
@@ -32,7 +33,10 @@ import com.android.internal.telecomm.IConnectionServiceAdapter;
oneway interface IConnectionService {
void addConnectionServiceAdapter(in IConnectionServiceAdapter adapter);
- void createConnection(in ConnectionRequest request, boolean isIncoming);
+ void createConnection(
+ in PhoneAccountHandle connectionManagerPhoneAccount,
+ in ConnectionRequest request,
+ boolean isIncoming);
void abort(String callId);
diff --git a/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
index 17e14aa..fc09a3a 100644
--- a/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
@@ -56,4 +56,8 @@ oneway interface IInCallAdapter {
void splitFromConference(String callId);
void swapWithBackgroundCall(String callId);
+
+ void turnOnProximitySensor();
+
+ void turnOffProximitySensor(boolean screenOnImmediately);
}
diff --git a/telephony/java/com/android/ims/ImsCallProfile.java b/telephony/java/com/android/ims/ImsCallProfile.java
index 6896f4d..adcb435 100644
--- a/telephony/java/com/android/ims/ImsCallProfile.java
+++ b/telephony/java/com/android/ims/ImsCallProfile.java
@@ -298,18 +298,18 @@ public class ImsCallProfile implements Parcelable {
public static int getVideoStateFromCallType(int callType) {
switch (callType) {
case CALL_TYPE_VT_NODIR:
- return VideoCallProfile.VIDEO_STATE_PAUSED |
- VideoCallProfile.VIDEO_STATE_BIDIRECTIONAL;
+ return VideoCallProfile.VideoState.PAUSED |
+ VideoCallProfile.VideoState.BIDIRECTIONAL;
case CALL_TYPE_VT_TX:
- return VideoCallProfile.VIDEO_STATE_TX_ENABLED;
+ return VideoCallProfile.VideoState.TX_ENABLED;
case CALL_TYPE_VT_RX:
- return VideoCallProfile.VIDEO_STATE_RX_ENABLED;
+ return VideoCallProfile.VideoState.RX_ENABLED;
case CALL_TYPE_VT:
- return VideoCallProfile.VIDEO_STATE_BIDIRECTIONAL;
+ return VideoCallProfile.VideoState.BIDIRECTIONAL;
case CALL_TYPE_VOICE:
- return VideoCallProfile.VIDEO_STATE_AUDIO_ONLY;
+ return VideoCallProfile.VideoState.AUDIO_ONLY;
default:
- return VideoCallProfile.VIDEO_STATE_AUDIO_ONLY;
+ return VideoCallProfile.VideoState.AUDIO_ONLY;
}
}
@@ -321,9 +321,9 @@ public class ImsCallProfile implements Parcelable {
* @return The call type.
*/
public static int getCallTypeFromVideoState(int videoState) {
- boolean videoTx = isVideoStateSet(videoState, VideoCallProfile.VIDEO_STATE_TX_ENABLED);
- boolean videoRx = isVideoStateSet(videoState, VideoCallProfile.VIDEO_STATE_RX_ENABLED);
- boolean isPaused = isVideoStateSet(videoState, VideoCallProfile.VIDEO_STATE_PAUSED);
+ boolean videoTx = isVideoStateSet(videoState, VideoCallProfile.VideoState.TX_ENABLED);
+ boolean videoRx = isVideoStateSet(videoState, VideoCallProfile.VideoState.RX_ENABLED);
+ boolean isPaused = isVideoStateSet(videoState, VideoCallProfile.VideoState.PAUSED);
if (isPaused) {
return ImsCallProfile.CALL_TYPE_VT_NODIR;
} else if (videoTx && !videoRx) {
diff --git a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
index bf8e887..e2c3be0 100644
--- a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
+++ b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
@@ -20,16 +20,21 @@ import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.app.job.JobParameters;
import android.app.job.JobService;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.os.AsyncTask;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
+import android.util.SparseArray;
import com.android.demo.jobSchedulerApp.MainActivity;
+import java.util.HashMap;
import java.util.LinkedList;
+import java.util.Random;
/**
@@ -75,39 +80,76 @@ public class TestJobService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
- jobParamsMap.add(params);
+ Log.i(TAG, "on start job: " + params.getJobId());
+ currentId++;
+ jobParamsMap.put(currentId, params);
+ final int currId = this.currentId;
+ Log.d(TAG, "putting :" + currId + " for " + params.toString());
+ Log.d(TAG, " pulled: " + jobParamsMap.get(currId));
if (mActivity != null) {
mActivity.onReceivedStartJob(params);
}
- Log.i(TAG, "on start job: " + params.getJobId());
+
+ // Spin off a new task on a separate thread for a couple seconds.
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... voids) {
+ try {
+ Log.d(TAG, "Sleeping for 3 seconds.");
+ Thread.sleep(3000L);
+ } catch (InterruptedException e) {}
+ final JobParameters params = jobParamsMap.get(currId);
+ Log.d(TAG, "Pulled :" + currId + " " + params);
+ jobFinished(params, false);
+
+ Log.d(TAG, "Rescheduling new job: " + params.getJobId());
+ scheduleJob(
+ new JobInfo.Builder(params.getJobId(),
+ new ComponentName(getBaseContext(), TestJobService.class))
+ .setMinimumLatency(2000L)
+ .setOverrideDeadline(3000L)
+ .setRequiresCharging(true)
+ .build()
+ );
+
+ return null;
+ }
+ }.execute();
return true;
}
+
@Override
public boolean onStopJob(JobParameters params) {
- jobParamsMap.remove(params);
- mActivity.onReceivedStopJob();
Log.i(TAG, "on stop job: " + params.getJobId());
+ int ind = jobParamsMap.indexOfValue(params);
+ jobParamsMap.remove(ind);
+ mActivity.onReceivedStopJob();
return true;
}
+ static int currentId = 0;
MainActivity mActivity;
- private final LinkedList<JobParameters> jobParamsMap = new LinkedList<JobParameters>();
+ private final SparseArray<JobParameters> jobParamsMap = new SparseArray<JobParameters>();
+
public void setUiCallback(MainActivity activity) {
mActivity = activity;
}
/** Send job to the JobScheduler. */
- public void scheduleJob(JobInfo t) {
- Log.d(TAG, "Scheduling job");
+ public void scheduleJob(JobInfo job) {
+ Log.d(TAG, "Scheduling job " + job);
JobScheduler tm =
(JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
- tm.schedule(t);
+ tm.schedule(job);
}
public boolean callJobFinished() {
- JobParameters params = jobParamsMap.poll();
+ if (jobParamsMap.size() == 0) {
+ return false;
+ }
+ JobParameters params = jobParamsMap.valueAt(0);
if (params == null) {
return false;
} else {
diff --git a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java
index 5d32c66..4372ff9 100644
--- a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java
+++ b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java
@@ -17,7 +17,10 @@
package android.hardware.soundtrigger;
import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.ConfidenceLevel;
import android.hardware.soundtrigger.SoundTrigger.Keyphrase;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
import android.os.Parcel;
@@ -253,4 +256,78 @@ public class SoundTriggerTest extends InstrumentationTestCase {
// Verify that they are the same
assertEquals(re, unparceled);
}
+
+ @SmallTest
+ public void testKeyphraseRecognitionEventParcelUnparcel_noKeyphrases() throws Exception {
+ KeyphraseRecognitionEvent re = new KeyphraseRecognitionEvent(
+ SoundTrigger.RECOGNITION_STATUS_SUCCESS, 1, true, 2, 3, 4, null, false, null);
+
+ // Write to a parcel
+ Parcel parcel = Parcel.obtain();
+ re.writeToParcel(parcel, 0);
+
+ // Read from it
+ parcel.setDataPosition(0);
+ KeyphraseRecognitionEvent unparceled =
+ KeyphraseRecognitionEvent.CREATOR.createFromParcel(parcel);
+
+ // Verify that they are the same
+ assertEquals(re, unparceled);
+ }
+
+ @SmallTest
+ public void testKeyphraseRecognitionEventParcelUnparcel_zeroData() throws Exception {
+ KeyphraseRecognitionExtra[] kpExtra = new KeyphraseRecognitionExtra[0];
+ KeyphraseRecognitionEvent re = new KeyphraseRecognitionEvent(
+ SoundTrigger.RECOGNITION_STATUS_FAILURE, 2, true, 2, 3, 4, new byte[1],
+ true, kpExtra);
+
+ // Write to a parcel
+ Parcel parcel = Parcel.obtain();
+ re.writeToParcel(parcel, 0);
+
+ // Read from it
+ parcel.setDataPosition(0);
+ KeyphraseRecognitionEvent unparceled =
+ KeyphraseRecognitionEvent.CREATOR.createFromParcel(parcel);
+
+ // Verify that they are the same
+ assertEquals(re, unparceled);
+ }
+
+ @LargeTest
+ public void testKeyphraseRecognitionEventParcelUnparcel_largeData() throws Exception {
+ byte[] data = new byte[200 * 1024];
+ mRandom.nextBytes(data);
+ KeyphraseRecognitionExtra[] kpExtra = new KeyphraseRecognitionExtra[4];
+ ConfidenceLevel cl1 = new ConfidenceLevel(1, 90);
+ ConfidenceLevel cl2 = new ConfidenceLevel(2, 30);
+ kpExtra[0] = new KeyphraseRecognitionExtra(1,
+ SoundTrigger.RECOGNITION_MODE_USER_IDENTIFICATION,
+ new ConfidenceLevel[] {cl1, cl2});
+ kpExtra[1] = new KeyphraseRecognitionExtra(1,
+ SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER,
+ new ConfidenceLevel[] {cl2});
+ kpExtra[2] = new KeyphraseRecognitionExtra(1,
+ SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER, null);
+ kpExtra[3] = new KeyphraseRecognitionExtra(1,
+ SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER,
+ new ConfidenceLevel[0]);
+
+ KeyphraseRecognitionEvent re = new KeyphraseRecognitionEvent(
+ SoundTrigger.RECOGNITION_STATUS_FAILURE, 1, true, 2, 3, 4, data,
+ false, kpExtra);
+
+ // Write to a parcel
+ Parcel parcel = Parcel.obtain();
+ re.writeToParcel(parcel, 0);
+
+ // Read from it
+ parcel.setDataPosition(0);
+ KeyphraseRecognitionEvent unparceled =
+ KeyphraseRecognitionEvent.CREATOR.createFromParcel(parcel);
+
+ // Verify that they are the same
+ assertEquals(re, unparceled);
+ }
}
diff --git a/tests/UsesFeature2Test/AndroidManifest.xml b/tests/UsesFeature2Test/AndroidManifest.xml
index 724d186..6b6c4da 100644
--- a/tests/UsesFeature2Test/AndroidManifest.xml
+++ b/tests/UsesFeature2Test/AndroidManifest.xml
@@ -30,6 +30,7 @@
</feature-group>
<feature-group android:label="@string/gamepad">
<uses-feature android:name="android.hardware.gamepad" />
+ <uses-feature android:name="android.hardware.opengles.aep" />
</feature-group>
<application android:label="@string/app_title">
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index ac1ae70..afeb546 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -611,6 +611,8 @@ struct ImpliedFeature {
* Represents a <feature-group> tag in the AndroidManifest.xml
*/
struct FeatureGroup {
+ FeatureGroup() : openGLESVersion(-1) {}
+
/**
* Human readable label
*/
@@ -620,6 +622,11 @@ struct FeatureGroup {
* Explicit features defined in the group
*/
KeyedVector<String8, bool> features;
+
+ /**
+ * OpenGL ES version required
+ */
+ int openGLESVersion;
};
static void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
@@ -637,6 +644,10 @@ static void printFeatureGroup(const FeatureGroup& grp,
const KeyedVector<String8, ImpliedFeature>* impliedFeatures = NULL) {
printf("feature-group: label='%s'\n", grp.label.string());
+ if (grp.openGLESVersion > 0) {
+ printf(" uses-gl-es: '0x%x'\n", grp.openGLESVersion);
+ }
+
const size_t numFeatures = grp.features.size();
for (size_t i = 0; i < numFeatures; i++) {
if (!grp.features[i]) {
@@ -688,6 +699,11 @@ static void addParentFeatures(FeatureGroup* grp, const String8& name) {
} else if (name == "android.hardware.touchscreen.multitouch.distinct") {
grp->features.add(String8("android.hardware.touchscreen.multitouch"), true);
grp->features.add(String8("android.hardware.touchscreen"), true);
+ } else if (name == "android.hardware.opengles.aep") {
+ const int openGLESVersion31 = 0x00030001;
+ if (openGLESVersion31 > grp->openGLESVersion) {
+ grp->openGLESVersion = openGLESVersion31;
+ }
}
}
@@ -1316,14 +1332,16 @@ int doDump(Bundle* bundle)
int vers = getIntegerAttribute(tree,
GL_ES_VERSION_ATTR, &error);
if (error == "") {
- printf("uses-gl-es:'0x%x'\n", vers);
+ if (vers > commonFeatures.openGLESVersion) {
+ commonFeatures.openGLESVersion = vers;
+ }
}
}
} else if (tag == "uses-permission") {
String8 name = getAttribute(tree, NAME_ATTR, &error);
if (name != "" && error == "") {
if (name == "android.permission.CAMERA") {
- addImpliedFeature(&impliedFeatures, "android.hardware.feature",
+ addImpliedFeature(&impliedFeatures, "android.hardware.camera",
String8::format("requested %s permission", name.string())
.string());
} else if (name == "android.permission.ACCESS_FINE_LOCATION") {
@@ -1639,18 +1657,23 @@ int doDump(Bundle* bundle)
}
}
} else if (withinFeatureGroup && tag == "uses-feature") {
+ FeatureGroup& top = featureGroups.editTop();
+
String8 name = getResolvedAttribute(&res, tree, NAME_ATTR, &error);
- if (error != "") {
- fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
- error.string());
- goto bail;
- }
+ if (name != "" && error == "") {
+ int required = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1);
+ top.features.add(name, required);
+ if (required) {
+ addParentFeatures(&top, name);
+ }
- int required = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1);
- FeatureGroup& top = featureGroups.editTop();
- top.features.add(name, required);
- if (required) {
- addParentFeatures(&top, name);
+ } else {
+ int vers = getIntegerAttribute(tree, GL_ES_VERSION_ATTR, &error);
+ if (error == "") {
+ if (vers > top.openGLESVersion) {
+ top.openGLESVersion = vers;
+ }
+ }
}
}
} else if (depth == 4) {
@@ -1839,12 +1862,17 @@ int doDump(Bundle* bundle)
for (size_t i = 0; i < numFeatureGroups; i++) {
FeatureGroup& grp = featureGroups.editItemAt(i);
+ if (commonFeatures.openGLESVersion > grp.openGLESVersion) {
+ grp.openGLESVersion = commonFeatures.openGLESVersion;
+ }
+
// Merge the features defined in the top level (not inside a <feature-group>)
// with this feature group.
const size_t numCommonFeatures = commonFeatures.features.size();
for (size_t j = 0; j < numCommonFeatures; j++) {
if (grp.features.indexOfKey(commonFeatures.features.keyAt(j)) < 0) {
- grp.features.add(commonFeatures.features.keyAt(j), commonFeatures.features[j]);
+ grp.features.add(commonFeatures.features.keyAt(j),
+ commonFeatures.features[j]);
}
}
diff --git a/wifi/java/android/net/wifi/WifiConnectionStatistics.java b/wifi/java/android/net/wifi/WifiConnectionStatistics.java
index 8e79a17..0046aa5 100644
--- a/wifi/java/android/net/wifi/WifiConnectionStatistics.java
+++ b/wifi/java/android/net/wifi/WifiConnectionStatistics.java
@@ -47,6 +47,15 @@ public class WifiConnectionStatistics implements Parcelable {
// Number of time we polled the chip and were on 2.4GHz
public int num24GhzConnected;
+ // Number autojoin attempts
+ public int numAutoJoinAttempt;
+
+ // Number auto-roam attempts
+ public int numAutoRoamAttempt;
+
+ // Number wifimanager join attempts
+ public int numWifiManagerJoinAttempt;
+
public WifiConnectionStatistics() {
untrustedNetworkHistory = new HashMap<String, WifiNetworkConnectionStatistics>();
}
@@ -74,6 +83,9 @@ public class WifiConnectionStatistics implements Parcelable {
StringBuilder sbuf = new StringBuilder();
sbuf.append("Connected on: 2.4Ghz=").append(num24GhzConnected);
sbuf.append(" 5Ghz=").append(num5GhzConnected).append("\n");
+ sbuf.append(" join=").append(numWifiManagerJoinAttempt);
+ sbuf.append("\\").append(numAutoJoinAttempt).append("\n");
+ sbuf.append(" roam=").append(numAutoRoamAttempt).append("\n");
for (String Key : untrustedNetworkHistory.keySet()) {
WifiNetworkConnectionStatistics stats = untrustedNetworkHistory.get(Key);
@@ -102,6 +114,10 @@ public class WifiConnectionStatistics implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(num24GhzConnected);
dest.writeInt(num5GhzConnected);
+ dest.writeInt(numAutoJoinAttempt);
+ dest.writeInt(numAutoRoamAttempt);
+ dest.writeInt(numWifiManagerJoinAttempt);
+
dest.writeInt(untrustedNetworkHistory.size());
for (String Key : untrustedNetworkHistory.keySet()) {
WifiNetworkConnectionStatistics num = untrustedNetworkHistory.get(Key);
@@ -119,6 +135,9 @@ public class WifiConnectionStatistics implements Parcelable {
WifiConnectionStatistics stats = new WifiConnectionStatistics();
stats.num24GhzConnected = in.readInt();
stats.num5GhzConnected = in.readInt();
+ stats.numAutoJoinAttempt = in.readInt();
+ stats.numAutoRoamAttempt = in.readInt();
+ stats.numWifiManagerJoinAttempt = in.readInt();
int n = in.readInt();
while (n-- > 0) {
String Key = in.readString();