diff options
885 files changed, 7222 insertions, 2970 deletions
@@ -276,6 +276,7 @@ LOCAL_SRC_FILES += \ core/java/com/android/internal/view/IInputMethodSession.aidl \ core/java/com/android/internal/view/IInputSessionCallback.aidl \ core/java/com/android/internal/widget/ILockSettings.aidl \ + core/java/com/android/internal/widget/ILockSettingsObserver.aidl \ core/java/com/android/internal/widget/IRemoteViewsFactory.aidl \ core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl \ keystore/java/android/security/IKeyChainAliasCallback.aidl \ diff --git a/api/current.txt b/api/current.txt index c38a82f..a829bdf 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5106,6 +5106,7 @@ package android.app.admin { method public void clearForwardingIntentFilters(android.content.ComponentName); method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String); method public void clearUserRestriction(android.content.ComponentName, java.lang.String); + method public 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 java.lang.String[] getAccountTypesWithManagementDisabled(); @@ -5139,6 +5140,7 @@ package android.app.admin { method public boolean isProfileOwnerApp(java.lang.String); method public void lockNow(); method public void removeActiveAdmin(android.content.ComponentName); + method public boolean removeUser(android.content.ComponentName, android.os.UserHandle); method public boolean resetPassword(java.lang.String, int); method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean); method public boolean setApplicationBlocked(android.content.ComponentName, java.lang.String, boolean); @@ -12134,83 +12136,119 @@ package android.hardware.camera2 { field public static final int CAMERA_ERROR = 3; // 0x3 } + public abstract class CameraCaptureSession implements java.lang.AutoCloseable { + ctor public CameraCaptureSession(); + method public abstract void abortCaptures() throws android.hardware.camera2.CameraAccessException; + method public abstract int capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method public abstract int captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method public abstract void close(); + method public abstract android.hardware.camera2.CameraDevice getDevice(); + method public abstract int setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method public abstract int setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method public abstract void stopRepeating() throws android.hardware.camera2.CameraAccessException; + } + + public static abstract class CameraCaptureSession.CaptureListener { + ctor public CameraCaptureSession.CaptureListener(); + method public void onCaptureCompleted(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult); + method public void onCaptureFailed(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureFailure); + method public void onCaptureSequenceCompleted(android.hardware.camera2.CameraDevice, int, int); + method public void onCaptureStarted(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, long); + } + + public static abstract class CameraCaptureSession.StateListener { + ctor public CameraCaptureSession.StateListener(); + method public void onActive(android.hardware.camera2.CameraCaptureSession); + method public void onClosed(android.hardware.camera2.CameraCaptureSession); + method public abstract void onConfigureFailed(android.hardware.camera2.CameraCaptureSession); + method public abstract void onConfigured(android.hardware.camera2.CameraCaptureSession); + method public void onReady(android.hardware.camera2.CameraCaptureSession); + } + public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata { - method public T get(android.hardware.camera2.CameraMetadata.Key<T>); - method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getAvailableCaptureRequestKeys(); - method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getAvailableCaptureResultKeys(); - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_AVAILABLE_ANTIBANDING_MODES; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_AVAILABLE_MODES; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_COMPENSATION_RANGE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_COMPENSATION_STEP; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_AVAILABLE_MODES; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AVAILABLE_EFFECTS; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AVAILABLE_SCENE_MODES; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_AVAILABLE_MODES; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_MAX_REGIONS; - field public static final android.hardware.camera2.CameraMetadata.Key EDGE_AVAILABLE_EDGE_MODES; - field public static final android.hardware.camera2.CameraMetadata.Key FLASH_INFO_AVAILABLE; - field public static final android.hardware.camera2.CameraMetadata.Key HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES; - field public static final android.hardware.camera2.CameraMetadata.Key INFO_SUPPORTED_HARDWARE_LEVEL; - field public static final android.hardware.camera2.CameraMetadata.Key JPEG_AVAILABLE_THUMBNAIL_SIZES; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_FACING; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_AVAILABLE_APERTURES; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_AVAILABLE_FILTER_DENSITIES; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_AVAILABLE_FOCAL_LENGTHS; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_FOCUS_DISTANCE_CALIBRATION; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_HYPERFOCAL_DISTANCE; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_MINIMUM_FOCUS_DISTANCE; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_SHADING_MAP_SIZE; - field public static final android.hardware.camera2.CameraMetadata.Key NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES; - field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_AVAILABLE_CAPABILITIES; - field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_MAX_NUM_INPUT_STREAMS; - field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_MAX_NUM_OUTPUT_STREAMS; - field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PARTIAL_RESULT_COUNT; - field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PIPELINE_MAX_DEPTH; - field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_MAX_DIGITAL_ZOOM; - field public static final android.hardware.camera2.CameraMetadata.Key SCALER_STREAM_CONFIGURATION_MAP; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_AVAILABLE_TEST_PATTERN_MODES; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_BASE_GAIN_FACTOR; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_BLACK_LEVEL_PATTERN; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_CALIBRATION_TRANSFORM1; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_CALIBRATION_TRANSFORM2; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_COLOR_TRANSFORM1; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_COLOR_TRANSFORM2; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FORWARD_MATRIX1; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FORWARD_MATRIX2; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_ACTIVE_ARRAY_SIZE; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_COLOR_FILTER_ARRANGEMENT; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_EXPOSURE_TIME_RANGE; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_MAX_FRAME_DURATION; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_PHYSICAL_SIZE; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_PIXEL_ARRAY_SIZE; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_SENSITIVITY_RANGE; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_WHITE_LEVEL; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_MAX_ANALOG_SENSITIVITY; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_ORIENTATION; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_REFERENCE_ILLUMINANT1; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_REFERENCE_ILLUMINANT2; - field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES; - field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES; - field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_MAX_FACE_COUNT; - field public static final android.hardware.camera2.CameraMetadata.Key SYNC_MAX_LATENCY; - field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_AVAILABLE_TONE_MAP_MODES; - field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MAX_CURVE_POINTS; + method public T get(android.hardware.camera2.CameraCharacteristics.Key<T>); + method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys(); + method public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys(); + field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_AVAILABLE_ANTIBANDING_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_AVAILABLE_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES; + field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_COMPENSATION_RANGE; + field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_COMPENSATION_STEP; + field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AF_AVAILABLE_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AVAILABLE_EFFECTS; + field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AVAILABLE_SCENE_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AWB_AVAILABLE_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_MAX_REGIONS; + field public static final android.hardware.camera2.CameraCharacteristics.Key EDGE_AVAILABLE_EDGE_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key FLASH_INFO_AVAILABLE; + field public static final android.hardware.camera2.CameraCharacteristics.Key HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key INFO_SUPPORTED_HARDWARE_LEVEL; + field public static final android.hardware.camera2.CameraCharacteristics.Key JPEG_AVAILABLE_THUMBNAIL_SIZES; + field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_FACING; + field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_AVAILABLE_APERTURES; + field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_AVAILABLE_FILTER_DENSITIES; + field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_AVAILABLE_FOCAL_LENGTHS; + field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION; + field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_FOCUS_DISTANCE_CALIBRATION; + field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_HYPERFOCAL_DISTANCE; + field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_MINIMUM_FOCUS_DISTANCE; + field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_SHADING_MAP_SIZE; + field public static final android.hardware.camera2.CameraCharacteristics.Key NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_AVAILABLE_CAPABILITIES; + field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_MAX_NUM_INPUT_STREAMS; + field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_MAX_NUM_OUTPUT_STREAMS; + field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_PARTIAL_RESULT_COUNT; + field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_PIPELINE_MAX_DEPTH; + field public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_AVAILABLE_MAX_DIGITAL_ZOOM; + field public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_CROPPING_TYPE; + field public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_STREAM_CONFIGURATION_MAP; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_AVAILABLE_TEST_PATTERN_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_BLACK_LEVEL_PATTERN; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_CALIBRATION_TRANSFORM1; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_CALIBRATION_TRANSFORM2; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_COLOR_TRANSFORM1; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_COLOR_TRANSFORM2; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_FORWARD_MATRIX1; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_FORWARD_MATRIX2; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_ACTIVE_ARRAY_SIZE; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_COLOR_FILTER_ARRANGEMENT; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_EXPOSURE_TIME_RANGE; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_MAX_FRAME_DURATION; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_PHYSICAL_SIZE; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_PIXEL_ARRAY_SIZE; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_SENSITIVITY_RANGE; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_WHITE_LEVEL; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_MAX_ANALOG_SENSITIVITY; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_ORIENTATION; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_REFERENCE_ILLUMINANT1; + field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_REFERENCE_ILLUMINANT2; + field public static final android.hardware.camera2.CameraCharacteristics.Key STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key STATISTICS_INFO_MAX_FACE_COUNT; + field public static final android.hardware.camera2.CameraCharacteristics.Key SYNC_MAX_LATENCY; + field public static final android.hardware.camera2.CameraCharacteristics.Key TONEMAP_AVAILABLE_TONE_MAP_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key TONEMAP_MAX_CURVE_POINTS; + } + + public static final class CameraCharacteristics.Key { + method public final boolean equals(java.lang.Object); + method public java.lang.String getName(); + method public final int hashCode(); } public abstract interface CameraDevice implements java.lang.AutoCloseable { - method public abstract int capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; - method public abstract int captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method public abstract deprecated int capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method public abstract deprecated int captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; method public abstract void close(); - method public abstract void configureOutputs(java.util.List<android.view.Surface>) throws android.hardware.camera2.CameraAccessException; + method public abstract deprecated void configureOutputs(java.util.List<android.view.Surface>) throws android.hardware.camera2.CameraAccessException; method public abstract android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int) throws android.hardware.camera2.CameraAccessException; - method public abstract void flush() throws android.hardware.camera2.CameraAccessException; + method public abstract void createCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method public abstract deprecated void flush() throws android.hardware.camera2.CameraAccessException; method public abstract java.lang.String getId(); - method public abstract int setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; - method public abstract int setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; - method public abstract void stopRepeating() throws android.hardware.camera2.CameraAccessException; + method public abstract deprecated int setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method public abstract deprecated int setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method public abstract deprecated void stopRepeating() throws android.hardware.camera2.CameraAccessException; field public static final int TEMPLATE_MANUAL = 6; // 0x6 field public static final int TEMPLATE_PREVIEW = 1; // 0x1 field public static final int TEMPLATE_RECORD = 3; // 0x3 @@ -12219,7 +12257,7 @@ package android.hardware.camera2 { field public static final int TEMPLATE_ZERO_SHUTTER_LAG = 5; // 0x5 } - public static abstract class CameraDevice.CaptureListener { + public static abstract deprecated class CameraDevice.CaptureListener { ctor public CameraDevice.CaptureListener(); method public void onCaptureCompleted(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult); method public void onCaptureFailed(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureFailure); @@ -12229,14 +12267,14 @@ package android.hardware.camera2 { public static abstract class CameraDevice.StateListener { ctor public CameraDevice.StateListener(); - method public void onActive(android.hardware.camera2.CameraDevice); - method public void onBusy(android.hardware.camera2.CameraDevice); + method public deprecated void onActive(android.hardware.camera2.CameraDevice); + method public deprecated void onBusy(android.hardware.camera2.CameraDevice); method public void onClosed(android.hardware.camera2.CameraDevice); method public abstract void onDisconnected(android.hardware.camera2.CameraDevice); method public abstract void onError(android.hardware.camera2.CameraDevice, int); - method public void onIdle(android.hardware.camera2.CameraDevice); + method public deprecated void onIdle(android.hardware.camera2.CameraDevice); method public abstract void onOpened(android.hardware.camera2.CameraDevice); - method public void onUnconfigured(android.hardware.camera2.CameraDevice); + method public deprecated void onUnconfigured(android.hardware.camera2.CameraDevice); field public static final int ERROR_CAMERA_DEVICE = 4; // 0x4 field public static final int ERROR_CAMERA_DISABLED = 3; // 0x3 field public static final int ERROR_CAMERA_IN_USE = 1; // 0x1 @@ -12259,8 +12297,7 @@ package android.hardware.camera2 { } public abstract class CameraMetadata { - method public abstract T get(android.hardware.camera2.CameraMetadata.Key<T>); - method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getKeys(); + method public java.util.List<TKey> getKeys(); field public static final int COLOR_CORRECTION_MODE_FAST = 1; // 0x1 field public static final int COLOR_CORRECTION_MODE_HIGH_QUALITY = 2; // 0x2 field public static final int COLOR_CORRECTION_MODE_TRANSFORM_MATRIX = 0; // 0x0 @@ -12380,6 +12417,8 @@ package android.hardware.camera2 { field public static final int REQUEST_AVAILABLE_CAPABILITIES_DNG = 5; // 0x5 field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 2; // 0x2 field public static final int REQUEST_AVAILABLE_CAPABILITIES_ZSL = 4; // 0x4 + field public static final int SCALER_CROPPING_TYPE_CENTER_ONLY = 0; // 0x0 + field public static final int SCALER_CROPPING_TYPE_FREEFORM = 1; // 0x1 field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR = 3; // 0x3 field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG = 2; // 0x2 field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG = 1; // 0x1 @@ -12428,12 +12467,6 @@ package android.hardware.camera2 { field public static final int TONEMAP_MODE_HIGH_QUALITY = 2; // 0x2 } - public static class CameraMetadata.Key { - method public final boolean equals(java.lang.Object); - method public final java.lang.String getName(); - method public final int hashCode(); - } - public class CaptureFailure { method public int getFrameNumber(); method public int getReason(); @@ -12446,146 +12479,170 @@ package android.hardware.camera2 { public final class CaptureRequest extends android.hardware.camera2.CameraMetadata implements android.os.Parcelable { method public int describeContents(); - method public T get(android.hardware.camera2.CameraMetadata.Key<T>); + method public T get(android.hardware.camera2.CaptureRequest.Key<T>); method public java.lang.Object getTag(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.hardware.camera2.CameraMetadata.Key BLACK_LEVEL_LOCK; - field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_GAINS; - field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_TRANSFORM; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_ANTIBANDING_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_EXPOSURE_COMPENSATION; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_LOCK; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_PRECAPTURE_TRIGGER; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_REGIONS; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_TARGET_FPS_RANGE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_REGIONS; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_TRIGGER; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_LOCK; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_REGIONS; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_CAPTURE_INTENT; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_EFFECT_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_SCENE_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_VIDEO_STABILIZATION_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key BLACK_LEVEL_LOCK; + field public static final android.hardware.camera2.CaptureRequest.Key COLOR_CORRECTION_GAINS; + field public static final android.hardware.camera2.CaptureRequest.Key COLOR_CORRECTION_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key COLOR_CORRECTION_TRANSFORM; + field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_ANTIBANDING_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_EXPOSURE_COMPENSATION; + field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_LOCK; + field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_PRECAPTURE_TRIGGER; + field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_REGIONS; + field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_TARGET_FPS_RANGE; + field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AF_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AF_REGIONS; + field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AF_TRIGGER; + field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AWB_LOCK; + field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AWB_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AWB_REGIONS; + field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_CAPTURE_INTENT; + field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_EFFECT_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_SCENE_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_VIDEO_STABILIZATION_MODE; field public static final android.os.Parcelable.Creator CREATOR; - field public static final android.hardware.camera2.CameraMetadata.Key EDGE_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key FLASH_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key HOT_PIXEL_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_COORDINATES; - field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_PROCESSING_METHOD; - field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_TIMESTAMP; - field public static final android.hardware.camera2.CameraMetadata.Key JPEG_ORIENTATION; - field public static final android.hardware.camera2.CameraMetadata.Key JPEG_QUALITY; - field public static final android.hardware.camera2.CameraMetadata.Key JPEG_THUMBNAIL_QUALITY; - field public static final android.hardware.camera2.CameraMetadata.Key JPEG_THUMBNAIL_SIZE; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_APERTURE; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_FILTER_DENSITY; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_FOCAL_LENGTH; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_FOCUS_DISTANCE; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_OPTICAL_STABILIZATION_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key NOISE_REDUCTION_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key SCALER_CROP_REGION; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_EXPOSURE_TIME; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FRAME_DURATION; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_DATA; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key SHADING_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_DETECT_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_HOT_PIXEL_MAP_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_BLUE; - field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_GREEN; - field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_RED; - field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key EDGE_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key FLASH_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key HOT_PIXEL_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key JPEG_GPS_COORDINATES; + field public static final android.hardware.camera2.CaptureRequest.Key JPEG_GPS_PROCESSING_METHOD; + field public static final android.hardware.camera2.CaptureRequest.Key JPEG_GPS_TIMESTAMP; + field public static final android.hardware.camera2.CaptureRequest.Key JPEG_ORIENTATION; + field public static final android.hardware.camera2.CaptureRequest.Key JPEG_QUALITY; + field public static final android.hardware.camera2.CaptureRequest.Key JPEG_THUMBNAIL_QUALITY; + field public static final android.hardware.camera2.CaptureRequest.Key JPEG_THUMBNAIL_SIZE; + field public static final android.hardware.camera2.CaptureRequest.Key LENS_APERTURE; + field public static final android.hardware.camera2.CaptureRequest.Key LENS_FILTER_DENSITY; + field public static final android.hardware.camera2.CaptureRequest.Key LENS_FOCAL_LENGTH; + field public static final android.hardware.camera2.CaptureRequest.Key LENS_FOCUS_DISTANCE; + field public static final android.hardware.camera2.CaptureRequest.Key LENS_OPTICAL_STABILIZATION_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key NOISE_REDUCTION_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key SCALER_CROP_REGION; + field public static final android.hardware.camera2.CaptureRequest.Key SENSOR_EXPOSURE_TIME; + field public static final android.hardware.camera2.CaptureRequest.Key SENSOR_FRAME_DURATION; + field public static final android.hardware.camera2.CaptureRequest.Key SENSOR_SENSITIVITY; + field public static final android.hardware.camera2.CaptureRequest.Key SENSOR_TEST_PATTERN_DATA; + field public static final android.hardware.camera2.CaptureRequest.Key SENSOR_TEST_PATTERN_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key SHADING_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key STATISTICS_FACE_DETECT_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key STATISTICS_HOT_PIXEL_MAP_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key STATISTICS_LENS_SHADING_MAP_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key TONEMAP_CURVE_BLUE; + field public static final android.hardware.camera2.CaptureRequest.Key TONEMAP_CURVE_GREEN; + field public static final android.hardware.camera2.CaptureRequest.Key TONEMAP_CURVE_RED; + field public static final android.hardware.camera2.CaptureRequest.Key TONEMAP_MODE; } public static final class CaptureRequest.Builder { method public void addTarget(android.view.Surface); method public android.hardware.camera2.CaptureRequest build(); - method public T get(android.hardware.camera2.CameraMetadata.Key<T>); + method public T get(android.hardware.camera2.CaptureRequest.Key<T>); method public void removeTarget(android.view.Surface); - method public void set(android.hardware.camera2.CameraMetadata.Key<T>, T); + method public void set(android.hardware.camera2.CaptureRequest.Key<T>, T); method public void setTag(java.lang.Object); } + public static final class CaptureRequest.Key { + method public final boolean equals(java.lang.Object); + method public java.lang.String getName(); + method public final int hashCode(); + } + public final class CaptureResult extends android.hardware.camera2.CameraMetadata { - method public T get(android.hardware.camera2.CameraMetadata.Key<T>); + method public T get(android.hardware.camera2.CaptureResult.Key<T>); method public int getFrameNumber(); method public android.hardware.camera2.CaptureRequest getRequest(); method public int getSequenceId(); - field public static final android.hardware.camera2.CameraMetadata.Key BLACK_LEVEL_LOCK; - field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_GAINS; - field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_TRANSFORM; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_ANTIBANDING_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_EXPOSURE_COMPENSATION; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_LOCK; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_PRECAPTURE_TRIGGER; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_REGIONS; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_STATE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_TARGET_FPS_RANGE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_REGIONS; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_STATE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_TRIGGER; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_LOCK; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_REGIONS; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_STATE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_CAPTURE_INTENT; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_EFFECT_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_SCENE_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_VIDEO_STABILIZATION_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key EDGE_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key FLASH_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key FLASH_STATE; - field public static final android.hardware.camera2.CameraMetadata.Key HOT_PIXEL_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_COORDINATES; - field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_PROCESSING_METHOD; - field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_TIMESTAMP; - field public static final android.hardware.camera2.CameraMetadata.Key JPEG_ORIENTATION; - field public static final android.hardware.camera2.CameraMetadata.Key JPEG_QUALITY; - field public static final android.hardware.camera2.CameraMetadata.Key JPEG_THUMBNAIL_QUALITY; - field public static final android.hardware.camera2.CameraMetadata.Key JPEG_THUMBNAIL_SIZE; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_APERTURE; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_FILTER_DENSITY; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_FOCAL_LENGTH; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_FOCUS_DISTANCE; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_FOCUS_RANGE; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_OPTICAL_STABILIZATION_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key LENS_STATE; - field public static final android.hardware.camera2.CameraMetadata.Key NOISE_REDUCTION_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_FRAME_COUNT; - field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PIPELINE_DEPTH; - field public static final android.hardware.camera2.CameraMetadata.Key SCALER_CROP_REGION; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_EXPOSURE_TIME; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FRAME_DURATION; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_GREEN_SPLIT; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_NEUTRAL_COLOR_POINT; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEMPERATURE; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_DATA; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TIMESTAMP; - field public static final android.hardware.camera2.CameraMetadata.Key SHADING_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACES; - field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_DETECT_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_HOT_PIXEL_MAP; - field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_HOT_PIXEL_MAP_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP; - field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP_MODE; - field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_SCENE_FLICKER; - field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_BLUE; - field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_GREEN; - field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_RED; - field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MODE; + field public static final android.hardware.camera2.CaptureResult.Key BLACK_LEVEL_LOCK; + field public static final android.hardware.camera2.CaptureResult.Key COLOR_CORRECTION_GAINS; + field public static final android.hardware.camera2.CaptureResult.Key COLOR_CORRECTION_MODE; + field public static final android.hardware.camera2.CaptureResult.Key COLOR_CORRECTION_TRANSFORM; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_ANTIBANDING_MODE; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_EXPOSURE_COMPENSATION; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_LOCK; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_MODE; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_PRECAPTURE_TRIGGER; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_REGIONS; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_STATE; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_TARGET_FPS_RANGE; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AF_MODE; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AF_REGIONS; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AF_STATE; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AF_TRIGGER; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AWB_LOCK; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AWB_MODE; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AWB_REGIONS; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AWB_STATE; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_CAPTURE_INTENT; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_EFFECT_MODE; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_MODE; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_SCENE_MODE; + field public static final android.hardware.camera2.CaptureResult.Key CONTROL_VIDEO_STABILIZATION_MODE; + field public static final android.hardware.camera2.CaptureResult.Key EDGE_MODE; + field public static final android.hardware.camera2.CaptureResult.Key FLASH_MODE; + field public static final android.hardware.camera2.CaptureResult.Key FLASH_STATE; + field public static final android.hardware.camera2.CaptureResult.Key HOT_PIXEL_MODE; + field public static final android.hardware.camera2.CaptureResult.Key JPEG_GPS_COORDINATES; + field public static final android.hardware.camera2.CaptureResult.Key JPEG_GPS_PROCESSING_METHOD; + field public static final android.hardware.camera2.CaptureResult.Key JPEG_GPS_TIMESTAMP; + field public static final android.hardware.camera2.CaptureResult.Key JPEG_ORIENTATION; + field public static final android.hardware.camera2.CaptureResult.Key JPEG_QUALITY; + field public static final android.hardware.camera2.CaptureResult.Key JPEG_THUMBNAIL_QUALITY; + field public static final android.hardware.camera2.CaptureResult.Key JPEG_THUMBNAIL_SIZE; + field public static final android.hardware.camera2.CaptureResult.Key LENS_APERTURE; + field public static final android.hardware.camera2.CaptureResult.Key LENS_FILTER_DENSITY; + field public static final android.hardware.camera2.CaptureResult.Key LENS_FOCAL_LENGTH; + field public static final android.hardware.camera2.CaptureResult.Key LENS_FOCUS_DISTANCE; + field public static final android.hardware.camera2.CaptureResult.Key LENS_FOCUS_RANGE; + 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; + field public static final android.hardware.camera2.CaptureResult.Key SENSOR_FRAME_DURATION; + field public static final android.hardware.camera2.CaptureResult.Key SENSOR_GREEN_SPLIT; + field public static final android.hardware.camera2.CaptureResult.Key SENSOR_NEUTRAL_COLOR_POINT; + field public static final android.hardware.camera2.CaptureResult.Key SENSOR_SENSITIVITY; + field public static final android.hardware.camera2.CaptureResult.Key SENSOR_TEST_PATTERN_DATA; + field public static final android.hardware.camera2.CaptureResult.Key SENSOR_TEST_PATTERN_MODE; + field public static final android.hardware.camera2.CaptureResult.Key SENSOR_TIMESTAMP; + field public static final android.hardware.camera2.CaptureResult.Key SHADING_MODE; + field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_FACES; + field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_FACE_DETECT_MODE; + field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_HOT_PIXEL_MAP; + field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_HOT_PIXEL_MAP_MODE; + field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_LENS_SHADING_MAP; + field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_LENS_SHADING_MAP_MODE; + field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_SCENE_FLICKER; + field public static final android.hardware.camera2.CaptureResult.Key TONEMAP_CURVE_BLUE; + field public static final android.hardware.camera2.CaptureResult.Key TONEMAP_CURVE_GREEN; + field public static final android.hardware.camera2.CaptureResult.Key TONEMAP_CURVE_RED; + field public static final android.hardware.camera2.CaptureResult.Key TONEMAP_MODE; + } + + public static final class CaptureResult.Key { + method public final boolean equals(java.lang.Object); + method public java.lang.String getName(); + method public final int hashCode(); + } + + public final class DngCreator implements java.lang.AutoCloseable { + ctor public DngCreator(android.hardware.camera2.CameraCharacteristics, android.hardware.camera2.CaptureResult); + method public void close(); + method public android.hardware.camera2.DngCreator setDescription(java.lang.String); + method public android.hardware.camera2.DngCreator setLocation(android.location.Location); + method public android.hardware.camera2.DngCreator setOrientation(int); + method public android.hardware.camera2.DngCreator setThumbnail(android.graphics.Bitmap); + method public android.hardware.camera2.DngCreator setThumbnail(android.media.Image); + method public void writeByteBuffer(java.io.OutputStream, android.util.Size, java.nio.ByteBuffer, long) throws java.io.IOException; + method public void writeImage(java.io.OutputStream, android.media.Image) throws java.io.IOException; + method public void writeInputStream(java.io.OutputStream, android.util.Size, java.io.InputStream, long) throws java.io.IOException; } } @@ -14056,19 +14113,6 @@ package android.media { ctor public DeniedByServerException(java.lang.String); } - public final class DngCreator implements java.lang.AutoCloseable { - ctor public DngCreator(android.hardware.camera2.CameraCharacteristics, android.hardware.camera2.CaptureResult); - method public void close(); - method public android.media.DngCreator setDescription(java.lang.String); - method public android.media.DngCreator setLocation(android.location.Location); - method public android.media.DngCreator setOrientation(int); - method public android.media.DngCreator setThumbnail(android.graphics.Bitmap); - method public android.media.DngCreator setThumbnail(android.media.Image); - method public void writeByteBuffer(java.io.OutputStream, android.util.Size, java.nio.ByteBuffer, long) throws java.io.IOException; - method public void writeImage(java.io.OutputStream, android.media.Image) throws java.io.IOException; - method public void writeInputStream(java.io.OutputStream, android.util.Size, java.io.InputStream, long) throws java.io.IOException; - } - public class ExifInterface { ctor public ExifInterface(java.lang.String) throws java.io.IOException; method public double getAltitude(double); @@ -25026,7 +25070,9 @@ package android.provider { field public static final java.lang.String COLUMN_DESCRIPTION = "description"; field public static final java.lang.String COLUMN_DISPLAY_NAME = "display_name"; field public static final java.lang.String COLUMN_DISPLAY_NUMBER = "display_number"; + field public static final java.lang.String COLUMN_LOCKED = "locked"; field public static final java.lang.String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id"; + field public static final java.lang.String COLUMN_SEARCHABLE = "searchable"; field public static final java.lang.String COLUMN_SERVICE_ID = "service_id"; field public static final java.lang.String COLUMN_SERVICE_NAME = "service_name"; field public static final java.lang.String COLUMN_SERVICE_TYPE = "service_type"; @@ -25064,10 +25110,12 @@ package android.provider { } public static final class TvContract.Programs implements android.provider.TvContract.BaseTvColumns { + field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language"; field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id"; field public static final java.lang.String COLUMN_DATA = "data"; field public static final java.lang.String COLUMN_DESCRIPTION = "description"; field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis"; + field public static final java.lang.String COLUMN_GENRE = "genre"; field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description"; field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis"; field public static final java.lang.String COLUMN_TITLE = "title"; diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 18e2a95..77b1acf 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -32,6 +32,7 @@ import android.os.RemoteCallback; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings; import android.service.trust.TrustAgentService; import android.util.Log; @@ -1983,6 +1984,43 @@ public class DevicePolicyManager { } /** + * Called by a device owner to create a user with the specified name. The UserHandle returned + * by this method should not be persisted as user handles are recycled as users are removed and + * created. If you need to persist an identifier for this user, use + * {@link UserManager#getSerialNumberForUser}. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param name the user's name + * @see UserHandle + * @return the UserHandle object for the created user, or null if the user could not be created. + */ + public UserHandle createUser(ComponentName admin, String name) { + try { + return mService.createUser(admin, name); + } catch (RemoteException re) { + Log.w(TAG, "Could not create a user", re); + } + return null; + } + + /** + * Called by a device owner to remove a user and all associated data. The primary user can + * not be removed. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param userHandle the user to remove. + * @return {@code true} if the user was removed, {@code false} otherwise. + */ + public boolean removeUser(ComponentName admin, UserHandle userHandle) { + try { + return mService.removeUser(admin, userHandle); + } catch (RemoteException re) { + Log.w(TAG, "Could not remove user ", re); + return false; + } + } + + /** * Called by a profile or device owner to get the application restrictions for a given target * application running in the managed profile. * diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 7257158..3c08c14 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -22,6 +22,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.RemoteCallback; +import android.os.UserHandle; /** * Internal IPC interface to the device policy service. @@ -128,6 +129,9 @@ interface IDevicePolicyManager { int setApplicationsBlocked(in ComponentName admin, in Intent intent, boolean blocked); boolean isApplicationBlocked(in ComponentName admin, in String packageName); + UserHandle createUser(in ComponentName who, in String name); + boolean removeUser(in ComponentName who, in UserHandle userHandle); + void enableSystemApp(in ComponentName admin, in String packageName); int enableSystemAppWithIntent(in ComponentName admin, in Intent intent); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index d0ac9c9..6ae006c 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1994,6 +1994,7 @@ public abstract class Context { WIFI_PASSPOINT_SERVICE, WIFI_P2P_SERVICE, WIFI_SCANNING_SERVICE, + //@hide: ETHERNET_SERVICE, NSD_SERVICE, AUDIO_SERVICE, MEDIA_ROUTER_SERVICE, @@ -2069,9 +2070,6 @@ public abstract class Context { * <dt> {@link #WIFI_P2P_SERVICE} ("wifip2p") * <dd> A {@link android.net.wifi.p2p.WifiP2pManager WifiP2pManager} for management of * Wi-Fi Direct connectivity. - * <dt> {@link #ETHERNET_SERVICE} ("ethernet") - * <dd> A {@link android.net.ethernet.EthernetManager EthernetManager} for - * management of Ethernet connectivity. * <dt> {@link #INPUT_METHOD_SERVICE} ("input_method") * <dd> An {@link android.view.inputmethod.InputMethodManager InputMethodManager} * for management of input methods. diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 076f657..f1391aa 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -45,6 +45,7 @@ import android.util.AttributeSet; import android.util.Log; import com.android.internal.util.XmlUtils; +import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.Serializable; @@ -604,6 +605,15 @@ import java.util.Set; * of all possible flags. */ public class Intent implements Parcelable, Cloneable { + private static final String ATTR_ACTION = "action"; + private static final String TAG_CATEGORIES = "categories"; + private static final String ATTR_CATEGORY = "category"; + private static final String TAG_EXTRA = "extra"; + private static final String ATTR_TYPE = "type"; + private static final String ATTR_COMPONENT = "component"; + private static final String ATTR_DATA = "data"; + private static final String ATTR_FLAGS = "flags"; + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Standard intent activity actions (see action variable). @@ -7347,7 +7357,7 @@ public class Intent implements Parcelable, Cloneable { } String nodeName = parser.getName(); - if (nodeName.equals("category")) { + if (nodeName.equals(TAG_CATEGORIES)) { sa = resources.obtainAttributes(attrs, com.android.internal.R.styleable.IntentCategory); String cat = sa.getString(com.android.internal.R.styleable.IntentCategory_name); @@ -7358,11 +7368,11 @@ public class Intent implements Parcelable, Cloneable { } XmlUtils.skipCurrentTag(parser); - } else if (nodeName.equals("extra")) { + } else if (nodeName.equals(TAG_EXTRA)) { if (intent.mExtras == null) { intent.mExtras = new Bundle(); } - resources.parseBundleExtra("extra", attrs, intent.mExtras); + resources.parseBundleExtra(TAG_EXTRA, attrs, intent.mExtras); XmlUtils.skipCurrentTag(parser); } else { @@ -7373,6 +7383,76 @@ public class Intent implements Parcelable, Cloneable { return intent; } + /** @hide */ + public void saveToXml(XmlSerializer out) throws IOException { + if (mAction != null) { + out.attribute(null, ATTR_ACTION, mAction); + } + if (mData != null) { + out.attribute(null, ATTR_DATA, mData.toString()); + } + if (mType != null) { + out.attribute(null, ATTR_TYPE, mType); + } + if (mComponent != null) { + out.attribute(null, ATTR_COMPONENT, mComponent.flattenToShortString()); + } + out.attribute(null, ATTR_FLAGS, Integer.toHexString(getFlags())); + + if (mCategories != null) { + out.startTag(null, TAG_CATEGORIES); + for (int categoryNdx = mCategories.size() - 1; categoryNdx >= 0; --categoryNdx) { + out.attribute(null, ATTR_CATEGORY, mCategories.valueAt(categoryNdx)); + } + } + } + + /** @hide */ + public static Intent restoreFromXml(XmlPullParser in) throws IOException, + XmlPullParserException { + Intent intent = new Intent(); + final int outerDepth = in.getDepth(); + + int attrCount = in.getAttributeCount(); + for (int attrNdx = attrCount - 1; attrNdx >= 0; --attrNdx) { + final String attrName = in.getAttributeName(attrNdx); + final String attrValue = in.getAttributeValue(attrNdx); + if (ATTR_ACTION.equals(attrName)) { + intent.setAction(attrValue); + } else if (ATTR_DATA.equals(attrName)) { + intent.setData(Uri.parse(attrValue)); + } else if (ATTR_TYPE.equals(attrName)) { + intent.setType(attrValue); + } else if (ATTR_COMPONENT.equals(attrName)) { + intent.setComponent(ComponentName.unflattenFromString(attrValue)); + } else if (ATTR_FLAGS.equals(attrName)) { + intent.setFlags(Integer.valueOf(attrValue, 16)); + } else { + Log.e("Intent", "restoreFromXml: unknown attribute=" + attrName); + } + } + + int event; + String name; + while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && + (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) { + if (event == XmlPullParser.START_TAG) { + name = in.getName(); + if (TAG_CATEGORIES.equals(name)) { + attrCount = in.getAttributeCount(); + for (int attrNdx = attrCount - 1; attrNdx >= 0; --attrNdx) { + intent.addCategory(in.getAttributeValue(attrNdx)); + } + } else { + Log.w("Intent", "restoreFromXml: unknown name=" + name); + XmlUtils.skipCurrentTag(in); + } + } + } + + return intent; + } + /** * Normalize a MIME data type. * diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index a78f8e2..3737638 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -31,11 +31,11 @@ import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.Trace; +import android.util.ArrayMap; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.util.Slog; -import android.util.SparseArray; import android.util.TypedValue; import android.util.LongSparseArray; @@ -104,10 +104,10 @@ public class Resources { // These are protected by mAccessLock. private final Object mAccessLock = new Object(); private final Configuration mTmpConfig = new Configuration(); - private final ThemedCaches<ConstantState> mDrawableCache = - new ThemedCaches<ConstantState>(); - private final ThemedCaches<ConstantState> mColorDrawableCache = - new ThemedCaches<ConstantState>(); + private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> mDrawableCache = + new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>(); + private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> mColorDrawableCache = + new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>(); private final LongSparseArray<WeakReference<ColorStateList>> mColorStateListCache = new LongSparseArray<WeakReference<ColorStateList>>(); @@ -1261,18 +1261,17 @@ public class Resources { * any of the style's attributes are already defined in the theme, the * current values in the theme will be overwritten. * - * @param resid The resource ID of a style resource from which to + * @param resId The resource ID of a style resource from which to * obtain attribute values. * @param force If true, values in the style resource will always be * used in the theme; otherwise, they will only be used * if not already defined in the theme. */ - public void applyStyle(int resid, boolean force) { - AssetManager.applyThemeStyle(mTheme, resid, force); + public void applyStyle(int resId, boolean force) { + AssetManager.applyThemeStyle(mTheme, resId, force); - // TODO: In very rare cases, we may end up with a hybrid theme - // that can't map to a single theme ID. - mThemeResId = resid; + mThemeResId = resId; + mKey += Integer.toHexString(resId) + (force ? "! " : " "); } /** @@ -1288,6 +1287,7 @@ public class Resources { AssetManager.copyTheme(mTheme, other.mTheme); mThemeResId = other.mThemeResId; + mKey = other.mKey; } /** @@ -1577,6 +1577,9 @@ public class Resources { /** Resource identifier for the theme. */ private int mThemeResId = 0; + /** Unique key for the series of styles applied to this theme. */ + private String mKey = ""; + // Needed by layoutlib. /*package*/ long getNativeTheme() { return mTheme; @@ -1585,6 +1588,10 @@ public class Resources { /*package*/ int getAppliedStyleResId() { return mThemeResId; } + + /*package*/ String getKey() { + return mKey; + } } /** @@ -1740,7 +1747,8 @@ public class Resources { } private void clearDrawableCachesLocked( - ThemedCaches<ConstantState> caches, int configChanges) { + ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches, + int configChanges) { final int N = caches.size(); for (int i = 0; i < N; i++) { clearDrawableCacheLocked(caches.valueAt(i), configChanges); @@ -1763,7 +1771,7 @@ public class Resources { configChanges, cs.getChangingConfigurations())) { if (DEBUG_CONFIG) { Log.d(TAG, "FLUSHING #0x" - + Long.toHexString(mDrawableCache.keyAt(i)) + + Long.toHexString(cache.keyAt(i)) + " / " + cs + " with changes: 0x" + Integer.toHexString(cs.getChangingConfigurations())); } @@ -2205,7 +2213,7 @@ public class Resources { } final boolean isColorDrawable; - final ThemedCaches<ConstantState> caches; + final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches; final long key; if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT && value.type <= TypedValue.TYPE_LAST_COLOR_INT) { @@ -2258,7 +2266,8 @@ public class Resources { } private void cacheDrawable(TypedValue value, Theme theme, boolean isColorDrawable, - ThemedCaches<ConstantState> caches, long key, Drawable dr) { + ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches, + long key, Drawable dr) { final ConstantState cs = dr.getConstantState(); if (cs == null) { return; @@ -2287,8 +2296,12 @@ public class Resources { } } else { synchronized (mAccessLock) { - final LongSparseArray<WeakReference<ConstantState>> themedCache; - themedCache = caches.getOrCreate(theme == null ? 0 : theme.mThemeResId); + final String themeKey = theme == null ? "" : theme.mKey; + LongSparseArray<WeakReference<ConstantState>> themedCache = caches.get(themeKey); + if (themedCache == null) { + themedCache = new LongSparseArray<WeakReference<ConstantState>>(1); + caches.put(themeKey, themedCache); + } themedCache.put(key, new WeakReference<ConstantState>(cs)); } } @@ -2347,7 +2360,9 @@ public class Resources { return dr; } - private Drawable getCachedDrawable(ThemedCaches<ConstantState> caches, long key, Theme theme) { + private Drawable getCachedDrawable( + ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches, + long key, Theme theme) { synchronized (mAccessLock) { final int themeKey = theme != null ? theme.mThemeResId : 0; final LongSparseArray<WeakReference<ConstantState>> themedCache = caches.get(themeKey); @@ -2584,21 +2599,4 @@ public class Resources { updateConfiguration(null, null); mAssets.ensureStringBlocks(); } - - static class ThemedCaches<T> extends SparseArray<LongSparseArray<WeakReference<T>>> { - /** - * Returns the cache of drawables styled for the specified theme. - * <p> - * Drawables that have themeable attributes but were loaded without - * specifying a theme are cached at themeResId = 0. - */ - public LongSparseArray<WeakReference<T>> getOrCreate(int themeResId) { - LongSparseArray<WeakReference<T>> result = get(themeResId); - if (result == null) { - result = new LongSparseArray<WeakReference<T>>(1); - put(themeResId, result); - } - return result; - } - } } diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java new file mode 100644 index 0000000..8391209 --- /dev/null +++ b/core/java/android/hardware/camera2/CameraCaptureSession.java @@ -0,0 +1,588 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.camera2; + +import android.os.Handler; +import java.util.List; + +/** + * A configured capture session for a {@link CameraDevice}, used for capturing + * images from the camera. + * + * <p>A CameraCaptureSession is created by providing a set of target output surfaces to + * {@link CameraDevice#createCaptureSession createCaptureSession}. Once created, the session is + * active until a new session is created by the camera device, or the camera device is closed.</p> + * + * <p>Creating a session is an expensive operation and can take several hundred milliseconds, since + * it requires configuring the camera device's internal pipelines and allocating memory buffers for + * sending images to the desired targets. While + * {@link CameraDevice#createCaptureSession createCaptureSession} will provide a + * CameraCaptureSession object immediately, configuration won't be complete until the + * {@link CameraCaptureSession.StateListener#onConfigured onConfigured} callback is called for the + * first time. If configuration cannot be completed, then the + * {@link CameraCaptureSession.StateListener#onConfigureFailed onConfigureFailed} is called, and the + * session will not become active.</p> + * + * <p>Any capture requests (repeating or non-repeating) submitted before the session is ready will + * be queued up and will begin capture once the session becomes ready. In case the session cannot be + * configured and {@link StateListener#onConfigureFailed onConfigureFailed} is called, all queued + * capture requests are discarded.</p> + * + * <p>If a new session is created by the camera device, then the previous session is closed, and its + * associated {@link StateListener#onClosed onClosed} callback will be invoked. All + * of the session methods will throw an IllegalStateException if called once the session is + * closed.</p> + * + * <p>A closed session clears any repeating requests (as if {@link #stopRepeating} had been called), + * but will still complete all of its in-progress capture requests as normal, before a newly + * created session takes over and reconfigures the camera device.</p> + */ +public abstract class CameraCaptureSession implements AutoCloseable { + + /** + * Get the camera device that this session is created for + */ + public abstract CameraDevice getDevice(); + + /** + * <p>Submit a request for an image to be captured by the camera device.</p> + * + * <p>The request defines all the parameters for capturing the single image, + * including sensor, lens, flash, and post-processing settings.</p> + * + * <p>Each request will produce one {@link CaptureResult} and produce new frames for one or more + * target Surfaces, set with the CaptureRequest builder's + * {@link CaptureRequest.Builder#addTarget} method. The target surfaces (set with + * {@link CaptureRequest.Builder#addTarget}) must be a subset of the surfaces provided when this + * capture session was created.</p> + * + * <p>Multiple requests can be in progress at once. They are processed in + * first-in, first-out order, with minimal delays between each + * capture. Requests submitted through this method have higher priority than + * those submitted through {@link #setRepeatingRequest} or + * {@link #setRepeatingBurst}, and will be processed as soon as the current + * repeat/repeatBurst processing completes.</p> + * + * @param request the settings for this capture + * @param listener The callback object to notify once this request has been + * processed. If null, no metadata will be produced for this capture, + * although image data will still be produced. + * @param handler the handler on which the listener should be invoked, or + * {@code null} to use the current thread's {@link android.os.Looper + * looper}. + * + * @return int A unique capture sequence ID used by + * {@link CaptureListener#onCaptureSequenceCompleted}. + * + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if this session is no longer active, either because a new + * session has been created or the camera device has been closed. + * @throws IllegalArgumentException if the request targets Surfaces that are not configured as + * outputs for this session. Or if the handler is null, the + * listener is not null, and the calling thread has no looper. + * + * @see #captureBurst + * @see #setRepeatingRequest + * @see #setRepeatingBurst + */ + public abstract int capture(CaptureRequest request, CaptureListener listener, Handler handler) + throws CameraAccessException; + + /** + * Submit a list of requests to be captured in sequence as a burst. The + * burst will be captured in the minimum amount of time possible, and will + * not be interleaved with requests submitted by other capture or repeat + * calls. + * + * <p>The requests will be captured in order, each capture producing one {@link CaptureResult} + * and image buffers for one or more target {@link android.view.Surface surfaces}. The target + * surfaces (set with {@link CaptureRequest.Builder#addTarget}) must be a subset of the surfaces + * provided when this capture session was created.</p> + * + * <p>The main difference between this method and simply calling + * {@link #capture} repeatedly is that this method guarantees that no + * other requests will be interspersed with the burst.</p> + * + * @param requests the list of settings for this burst capture + * @param listener The callback object to notify each time one of the + * requests in the burst has been processed. If null, no metadata will be + * produced for any requests in this burst, although image data will still + * be produced. + * @param handler the handler on which the listener should be invoked, or + * {@code null} to use the current thread's {@link android.os.Looper + * looper}. + * + * @return int A unique capture sequence ID used by + * {@link CaptureListener#onCaptureSequenceCompleted}. + * + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if this session is no longer active, either because a new + * session has been created or the camera device has been closed. + * @throws IllegalArgumentException If the requests target Surfaces not currently configured as + * outputs. Or if the handler is null, the listener is not + * null, and the calling thread has no looper. + * + * @see #capture + * @see #setRepeatingRequest + * @see #setRepeatingBurst + */ + public abstract int captureBurst(List<CaptureRequest> requests, CaptureListener listener, + Handler handler) throws CameraAccessException; + + /** + * Request endlessly repeating capture of images by this capture session. + * + * <p>With this method, the camera device will continually capture images + * using the settings in the provided {@link CaptureRequest}, at the maximum + * rate possible.</p> + * + * <p>Repeating requests are a simple way for an application to maintain a + * preview or other continuous stream of frames, without having to + * continually submit identical requests through {@link #capture}.</p> + * + * <p>Repeat requests have lower priority than those submitted + * through {@link #capture} or {@link #captureBurst}, so if + * {@link #capture} is called when a repeating request is active, the + * capture request will be processed before any further repeating + * requests are processed.<p> + * + * <p>Repeating requests are a simple way for an application to maintain a + * preview or other continuous stream of frames, without having to submit + * requests through {@link #capture} at video rates.</p> + * + * <p>To stop the repeating capture, call {@link #stopRepeating}. Calling + * {@link #abortCaptures} will also clear the request.</p> + * + * <p>Calling this method will replace any earlier repeating request or + * burst set up by this method or {@link #setRepeatingBurst}, although any + * in-progress burst will be completed before the new repeat request will be + * used.</p> + * + * @param request the request to repeat indefinitely + * @param listener The callback object to notify every time the + * request finishes processing. If null, no metadata will be + * produced for this stream of requests, although image data will + * still be produced. + * @param handler the handler on which the listener should be invoked, or + * {@code null} to use the current thread's {@link android.os.Looper + * looper}. + * + * @return int A unique capture sequence ID used by + * {@link CaptureListener#onCaptureSequenceCompleted}. + * + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if this session is no longer active, either because a new + * session has been created or the camera device has been closed. + * @throws IllegalArgumentException If the requests reference Surfaces that are not currently + * configured as outputs. Or if the handler is null, the + * listener is not null, and the calling thread has no looper. + * + * @see #capture + * @see #captureBurst + * @see #setRepeatingBurst + * @see #stopRepeating + * @see #abortCaptures + */ + public abstract int setRepeatingRequest(CaptureRequest request, CaptureListener listener, + Handler handler) throws CameraAccessException; + + /** + * <p>Request endlessly repeating capture of a sequence of images by this + * capture session.</p> + * + * <p>With this method, the camera device will continually capture images, + * cycling through the settings in the provided list of + * {@link CaptureRequest CaptureRequests}, at the maximum rate possible.</p> + * + * <p>If a request is submitted through {@link #capture} or + * {@link #captureBurst}, the current repetition of the request list will be + * completed before the higher-priority request is handled. This guarantees + * that the application always receives a complete repeat burst captured in + * minimal time, instead of bursts interleaved with higher-priority + * captures, or incomplete captures.</p> + * + * <p>Repeating burst requests are a simple way for an application to + * maintain a preview or other continuous stream of frames where each + * request is different in a predicatable way, without having to continually + * submit requests through {@link #captureBurst}.</p> + * + * <p>To stop the repeating capture, call {@link #stopRepeating}. Any + * ongoing burst will still be completed, however. Calling + * {@link #abortCaptures} will also clear the request.</p> + * + * <p>Calling this method will replace a previously-set repeating request or + * burst set up by this method or {@link #setRepeatingRequest}, although any + * in-progress burst will be completed before the new repeat burst will be + * used.</p> + * + * @param requests the list of requests to cycle through indefinitely + * @param listener The callback object to notify each time one of the + * requests in the repeating bursts has finished processing. If null, no + * metadata will be produced for this stream of requests, although image + * data will still be produced. + * @param handler the handler on which the listener should be invoked, or + * {@code null} to use the current thread's {@link android.os.Looper + * looper}. + * + * @return int A unique capture sequence ID used by + * {@link CaptureListener#onCaptureSequenceCompleted}. + * + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if this session is no longer active, either because a new + * session has been created or the camera device has been closed. + * @throws IllegalArgumentException If the requests reference Surfaces not currently configured + * as outputs. Or if the handler is null, the listener is not + * null, and the calling thread has no looper. + * + * @see #capture + * @see #captureBurst + * @see #setRepeatingRequest + * @see #stopRepeating + * @see #abortCaptures + */ + public abstract int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener, + Handler handler) throws CameraAccessException; + + /** + * <p>Cancel any ongoing repeating capture set by either + * {@link #setRepeatingRequest setRepeatingRequest} or + * {@link #setRepeatingBurst}. Has no effect on requests submitted through + * {@link #capture capture} or {@link #captureBurst captureBurst}.</p> + * + * <p>Any currently in-flight captures will still complete, as will any burst that is + * mid-capture. To ensure that the device has finished processing all of its capture requests + * and is in ready state, wait for the {@link StateListener#onReady} callback after + * calling this method.</p> + * + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if this session is no longer active, either because a new + * session has been created or the camera device has been closed. + * + * @see #setRepeatingRequest + * @see #setRepeatingBurst + * @see StateListener#onIdle + */ + public abstract void stopRepeating() throws CameraAccessException; + + /** + * Discard all captures currently pending and in-progress as fast as possible. + * + * <p>The camera device will discard all of its current work as fast as possible. Some in-flight + * captures may complete successfully and call {@link CaptureListener#onCaptureCompleted}, while + * others will trigger their {@link CaptureListener#onCaptureFailed} callbacks. If a repeating + * request or a repeating burst is set, it will be cleared.</p> + * + * <p>This method is the fastest way to switch the camera device to a new session with + * {@link CameraDevice#createCaptureSession}, at the cost of discarding in-progress work. It + * must be called before the new session is created. Once all pending requests are either + * completed or thrown away, the {@link StateListener#onReady} callback will be called, + * if the session has not been closed. Otherwise, the {@link StateListener#onClosed} + * callback will be fired when a new session is created by the camera device.</p> + * + * <p>Cancelling will introduce at least a brief pause in the stream of data from the camera + * device, since once the camera device is emptied, the first new request has to make it through + * the entire camera pipeline before new output buffers are produced.</p> + * + * <p>This means that using {@code abortCaptures()} to simply remove pending requests is not + * recommended; it's best used for quickly switching output configurations, or for cancelling + * long in-progress requests (such as a multi-second capture).</p> + * + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if this session is no longer active, either because a new + * session has been created or the camera device has been closed. + * + * @see #setRepeatingRequest + * @see #setRepeatingBurst + * @see #configureOutputs + */ + public abstract void abortCaptures() throws CameraAccessException; + + /** + * Close this capture session asynchronously. + * + * <p>Closing a session frees up the target output Surfaces of the session for reuse with either a + * new session, or to other APIs that can draw to Surfaces.</p> + * + * <p>Note that creating a new capture session with {@link CameraDevice#createCaptureSession} + * will close any existing capture session automatically, and call the older session listener's + * {@link StateListener#onClosed} callback. Using {@link CameraDevice#createCaptureSession} + * directly without closing is the recommended approach for quickly switching to a new session, + * since unchanged target outputs can be reused more efficiently.</p> + * + * <p>Once a session is closed, all methods on it will throw an IllegalStateException, and any + * repeating requests or bursts are stopped (as if {@link #stopRepeating()} was called). + * However, any in-progress capture requests submitted to the session will be completed as + * normal; once all captures have completed and the session has been torn down, + * {@link StateListener#onClosed} will be called.</p> + */ + @Override + public abstract void close(); + + /** + * A listener for tracking the state of a camera capture session. + * + */ + public static abstract class StateListener { + + /** + * This method is called when the camera device has finished configuring itself, and the + * session can start processing capture requests. + * + * <p>If there are capture requests already queued with the session, they will start + * processing once this callback is invoked, and the session will call {@link #onActive} + * right after this callback is invoked.</p> + * + * <p>If no capture requests have been submitted, then the session will invoke + * {@link #onReady} right after this callback.</p> + * + * <p>If the camera device configuration fails, then {@link #onConfigureFailed} will + * be invoked instead of this callback.</p> + * + */ + public abstract void onConfigured(CameraCaptureSession session); + + /** + * This method is called if the session cannot be configured as requested. + * + * <p>This can happen if the set of requested outputs contains unsupported sizes, + * or too many outputs are requested at once.</p> + * + * <p>The session is considered to be closed, and all methods called on it after this + * callback is invoked will throw an IllegalStateException. Any capture requests submitted + * to the session prior to this callback will be discarded and will not produce any + * callbacks on their listeners.</p> + */ + public abstract void onConfigureFailed(CameraCaptureSession session); + + /** + * This method is called every time the session has no more capture requests to process. + * + * <p>During the creation of a new session, this callback is invoked right after + * {@link #onConfigured} if no capture requests were submitted to the session prior to it + * completing configuration.</p> + * + * <p>Otherwise, this callback will be invoked any time the session finishes processing + * all of its active capture requests, and no repeating request or burst is set up.</p> + * + */ + public void onReady(CameraCaptureSession session) { + // default empty implementation + } + + /** + * This method is called when the session starts actively processing capture requests. + * + * <p>If capture requests are submitted prior to {@link #onConfigured} being called, + * then the session will start processing those requests immediately after the callback, + * and this method will be immediately called after {@link #onConfigured}. + * + * <p>If the session runs out of capture requests to process and calls {@link #onReady}, + * then this callback will be invoked again once new requests are submitted for capture.</p> + */ + public void onActive(CameraCaptureSession session) { + // default empty implementation + } + + /** + * This method is called when the session is closed. + * + * <p>A session is closed when a new session is created by the parent camera device, + * or when the parent camera device is closed (either by the user closing the device, + * or due to a camera device disconnection or fatal error).</p> + * + * <p>Once a session is closed, all methods on it will throw an IllegalStateException, and + * any repeating requests or bursts are stopped (as if {@link #stopRepeating()} was called). + * However, any in-progress capture requests submitted to the session will be completed + * as normal.</p> + */ + public void onClosed(CameraCaptureSession session) { + // default empty implementation + } + } + + /** + * <p>A listener for tracking the progress of a {@link CaptureRequest} + * submitted to the camera device.</p> + * + * <p>This listener is called when a request triggers a capture to start, + * and when the capture is complete. In case on an error capturing an image, + * the error method is triggered instead of the completion method.</p> + * + * @see #capture + * @see #captureBurst + * @see #setRepeatingRequest + * @see #setRepeatingBurst + */ + public static abstract class CaptureListener { + + /** + * This constant is used to indicate that no images were captured for + * the request. + * + * @hide + */ + public static final int NO_FRAMES_CAPTURED = -1; + + /** + * This method is called when the camera device has started capturing + * the output image for the request, at the beginning of image exposure. + * + * <p>This callback is invoked right as the capture of a frame begins, + * so it is the most appropriate time for playing a shutter sound, + * or triggering UI indicators of capture.</p> + * + * <p>The request that is being used for this capture is provided, along + * with the actual timestamp for the start of exposure. This timestamp + * matches the timestamp that will be included in + * {@link CaptureResult#SENSOR_TIMESTAMP the result timestamp field}, + * and in the buffers sent to each output Surface. These buffer + * timestamps are accessible through, for example, + * {@link android.media.Image#getTimestamp() Image.getTimestamp()} or + * {@link android.graphics.SurfaceTexture#getTimestamp()}.</p> + * + * <p>For the simplest way to play a shutter sound camera shutter or a + * video recording start/stop sound, see the + * {@link android.media.MediaActionSound} class.</p> + * + * <p>The default implementation of this method does nothing.</p> + * + * @param camera the CameraDevice sending the callback + * @param request the request for the capture that just begun + * @param timestamp the timestamp at start of capture, in nanoseconds. + * + * @see android.media.MediaActionSound + */ + public void onCaptureStarted(CameraDevice camera, + CaptureRequest request, long timestamp) { + // default empty implementation + } + + /** + * This method is called when some results from an image capture are + * available. + * + * <p>The result provided here will contain some subset of the fields of + * a full result. Multiple onCapturePartial calls may happen per + * capture; a given result field will only be present in one partial + * capture at most. The final onCaptureCompleted call will always + * contain all the fields, whether onCapturePartial was called or + * not.</p> + * + * <p>The default implementation of this method does nothing.</p> + * + * @param camera The CameraDevice sending the callback. + * @param request The request that was given to the CameraDevice + * @param result The partial output metadata from the capture, which + * includes a subset of the CaptureResult fields. + * + * @see #capture + * @see #captureBurst + * @see #setRepeatingRequest + * @see #setRepeatingBurst + * + * @hide + */ + public void onCapturePartial(CameraDevice camera, + CaptureRequest request, CaptureResult result) { + // default empty implementation + } + + /** + * This method is called when an image capture has completed and the + * result metadata is available. + * + * <p>The default implementation of this method does nothing.</p> + * + * @param camera The CameraDevice sending the callback. + * @param request The request that was given to the CameraDevice + * @param result The output metadata from the capture, including the + * final capture parameters and the state of the camera system during + * capture. + * + * @see #capture + * @see #captureBurst + * @see #setRepeatingRequest + * @see #setRepeatingBurst + */ + public void onCaptureCompleted(CameraDevice camera, + CaptureRequest request, CaptureResult result) { + // default empty implementation + } + + /** + * This method is called instead of {@link #onCaptureCompleted} when the + * camera device failed to produce a {@link CaptureResult} for the + * request. + * + * <p>Other requests are unaffected, and some or all image buffers from + * the capture may have been pushed to their respective output + * streams.</p> + * + * <p>The default implementation of this method does nothing.</p> + * + * @param camera + * The CameraDevice sending the callback. + * @param request + * The request that was given to the CameraDevice + * @param failure + * The output failure from the capture, including the failure reason + * and the frame number. + * + * @see #capture + * @see #captureBurst + * @see #setRepeatingRequest + * @see #setRepeatingBurst + */ + public void onCaptureFailed(CameraDevice camera, + CaptureRequest request, CaptureFailure failure) { + // default empty implementation + } + + /** + * This method is called independently of the others in CaptureListener, + * when a capture sequence finishes and all {@link CaptureResult} + * or {@link CaptureFailure} for it have been returned via this listener. + * + * @param camera + * The CameraDevice sending the callback. + * @param sequenceId + * A sequence ID returned by the {@link #capture} family of functions. + * @param lastFrameNumber + * The last frame number (returned by {@link CaptureResult#getFrameNumber} + * or {@link CaptureFailure#getFrameNumber}) in the capture sequence. + * The last frame number may be equal to NO_FRAMES_CAPTURED if no images + * were captured for this sequence. This can happen, for example, when a + * repeating request or burst is cleared right after being set. + * + * @see CaptureResult#getFrameNumber() + * @see CaptureFailure#getFrameNumber() + * @see CaptureResult#getSequenceId() + * @see CaptureFailure#getSequenceId() + */ + public void onCaptureSequenceCompleted(CameraDevice camera, + int sequenceId, int lastFrameNumber) { + // default empty implementation + } + } + +} diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 7cc6d1d..c08424a 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -16,7 +16,9 @@ package android.hardware.camera2; +import android.hardware.camera2.CaptureResult.Key; import android.hardware.camera2.impl.CameraMetadataNative; +import android.hardware.camera2.utils.TypeReference; import android.util.Rational; import java.util.Collections; @@ -35,18 +37,109 @@ import java.util.List; * @see CameraDevice * @see CameraManager */ -public final class CameraCharacteristics extends CameraMetadata { +public final class CameraCharacteristics extends CameraMetadata<CameraCharacteristics.Key<?>> { + + /** + * A {@code Key} is used to do camera characteristics field lookups with + * {@link CameraCharacteristics#get}. + * + * <p>For example, to get the stream configuration map: + * <code><pre> + * StreamConfigurationMap map = cameraCharacteristics.get( + * CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); + * </pre></code> + * </p> + * + * <p>To enumerate over all possible keys for {@link CameraCharacteristics}, see + * {@link CameraCharacteristics#getKeys()}.</p> + * + * @see CameraCharacteristics#get + * @see CameraCharacteristics#getKeys() + */ + public static final class Key<T> { + private final CameraMetadataNative.Key<T> mKey; + + /** + * Visible for testing and vendor extensions only. + * + * @hide + */ + public Key(String name, Class<T> type) { + mKey = new CameraMetadataNative.Key<T>(name, type); + } + + /** + * Visible for testing and vendor extensions only. + * + * @hide + */ + public Key(String name, TypeReference<T> typeReference) { + mKey = new CameraMetadataNative.Key<T>(name, typeReference); + } + + /** + * Return a camelCase, period separated name formatted like: + * {@code "root.section[.subsections].name"}. + * + * <p>Built-in keys exposed by the Android SDK are always prefixed with {@code "android."}; + * keys that are device/platform-specific are prefixed with {@code "com."}.</p> + * + * <p>For example, {@code CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP} would + * have a name of {@code "android.scaler.streamConfigurationMap"}; whereas a device + * specific key might look like {@code "com.google.nexus.data.private"}.</p> + * + * @return String representation of the key name + */ + public String getName() { + return mKey.getName(); + } + + /** + * {@inheritDoc} + */ + @Override + public final int hashCode() { + return mKey.hashCode(); + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings("unchecked") + @Override + public final boolean equals(Object o) { + return o instanceof Key && ((Key<T>)o).mKey.equals(mKey); + } + + /** + * Visible for CameraMetadataNative implementation only; do not use. + * + * TODO: Make this private or remove it altogether. + * + * @hide + */ + public CameraMetadataNative.Key<T> getNativeKey() { + return mKey; + } + + @SuppressWarnings({ + "unused", "unchecked" + }) + private Key(CameraMetadataNative.Key<?> nativeKey) { + mKey = (CameraMetadataNative.Key<T>) nativeKey; + } + } private final CameraMetadataNative mProperties; - private List<Key<?>> mAvailableRequestKeys; - private List<Key<?>> mAvailableResultKeys; + private List<CaptureRequest.Key<?>> mAvailableRequestKeys; + private List<CaptureResult.Key<?>> mAvailableResultKeys; /** * Takes ownership of the passed-in properties object * @hide */ public CameraCharacteristics(CameraMetadataNative properties) { - mProperties = properties; + mProperties = CameraMetadataNative.move(properties); } /** @@ -57,12 +150,55 @@ public final class CameraCharacteristics extends CameraMetadata { return new CameraMetadataNative(mProperties); } - @Override + /** + * Get a camera characteristics field value. + * + * <p>The field definitions can be + * found in {@link CameraCharacteristics}.</p> + * + * <p>Querying the value for the same key more than once will return a value + * which is equal to the previous queried value.</p> + * + * @throws IllegalArgumentException if the key was not valid + * + * @param key The characteristics field to read. + * @return The value of that key, or {@code null} if the field is not set. + */ public <T> T get(Key<T> key) { return mProperties.get(key); } /** + * {@inheritDoc} + * @hide + */ + @SuppressWarnings("unchecked") + @Override + protected <T> T getProtected(Key<?> key) { + return (T) mProperties.get(key); + } + + /** + * {@inheritDoc} + * @hide + */ + @SuppressWarnings("unchecked") + @Override + protected Class<Key<?>> getKeyClass() { + Object thisClass = Key.class; + return (Class<Key<?>>)thisClass; + } + + /** + * {@inheritDoc} + */ + @Override + public List<Key<?>> getKeys() { + // Force the javadoc for this function to show up on the CameraCharacteristics page + return super.getKeys(); + } + + /** * Returns the list of keys supported by this {@link CameraDevice} for querying * with a {@link CaptureRequest}. * @@ -76,9 +212,14 @@ public final class CameraCharacteristics extends CameraMetadata { * * @return List of keys supported by this CameraDevice for CaptureRequests. */ - public List<Key<?>> getAvailableCaptureRequestKeys() { + @SuppressWarnings({"unchecked"}) + public List<CaptureRequest.Key<?>> getAvailableCaptureRequestKeys() { if (mAvailableRequestKeys == null) { - mAvailableRequestKeys = getAvailableKeyList(CaptureRequest.class); + Object crKey = CaptureRequest.Key.class; + Class<CaptureRequest.Key<?>> crKeyTyped = (Class<CaptureRequest.Key<?>>)crKey; + + mAvailableRequestKeys = Collections.unmodifiableList( + getAvailableKeyList(CaptureRequest.class, crKeyTyped)); } return mAvailableRequestKeys; } @@ -97,9 +238,14 @@ public final class CameraCharacteristics extends CameraMetadata { * * @return List of keys supported by this CameraDevice for CaptureResults. */ - public List<Key<?>> getAvailableCaptureResultKeys() { + @SuppressWarnings({"unchecked"}) + public List<CaptureResult.Key<?>> getAvailableCaptureResultKeys() { if (mAvailableResultKeys == null) { - mAvailableResultKeys = getAvailableKeyList(CaptureResult.class); + Object crKey = CaptureResult.Key.class; + Class<CaptureResult.Key<?>> crKeyTyped = (Class<CaptureResult.Key<?>>)crKey; + + mAvailableResultKeys = Collections.unmodifiableList( + getAvailableKeyList(CaptureResult.class, crKeyTyped)); } return mAvailableResultKeys; } @@ -113,12 +259,14 @@ public final class CameraCharacteristics extends CameraMetadata { * <p>Each key is only listed once in the list. The order of the keys is undefined.</p> * * @param metadataClass The subclass of CameraMetadata that you want to get the keys for. + * @param keyClass The class of the metadata key, e.g. CaptureRequest.Key.class * * @return List of keys supported by this CameraDevice for metadataClass. * * @throws IllegalArgumentException if metadataClass is not a subclass of CameraMetadata */ - private <T extends CameraMetadata> List<Key<?>> getAvailableKeyList(Class<T> metadataClass) { + private <TKey> List<TKey> + getAvailableKeyList(Class<?> metadataClass, Class<TKey> keyClass) { if (metadataClass.equals(CameraMetadata.class)) { throw new AssertionError( @@ -128,7 +276,9 @@ public final class CameraCharacteristics extends CameraMetadata { "metadataClass must be a subclass of CameraMetadata"); } - return Collections.unmodifiableList(getKeysStatic(metadataClass, /*instance*/null)); + List<TKey> staticKeyList = CameraCharacteristics.<TKey>getKeysStatic( + metadataClass, keyClass, /*instance*/null); + return Collections.unmodifiableList(staticKeyList); } /*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~ @@ -1046,6 +1196,28 @@ public final class CameraCharacteristics extends CameraMetadata { new Key<android.hardware.camera2.params.StreamConfigurationMap>("android.scaler.streamConfigurationMap", android.hardware.camera2.params.StreamConfigurationMap.class); /** + * <p>The crop type that this camera device supports.</p> + * <p>When passing a non-centered crop region ({@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}) to a camera + * device that only supports CENTER_ONLY cropping, the camera device will move the + * crop region to the center of the sensor active array ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}) + * and keep the crop region width and height unchanged. The camera device will return the + * final used crop region in metadata result {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}.</p> + * <p>Camera devices that support FREEFORM cropping will support any crop region that + * is inside of the active array. The camera device will apply the same crop region and + * return the final used crop region in capture result metadata {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}.</p> + * <p>FULL capability devices ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} <code>==</code> FULL) will support + * FREEFORM cropping.</p> + * + * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL + * @see CaptureRequest#SCALER_CROP_REGION + * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see #SCALER_CROPPING_TYPE_CENTER_ONLY + * @see #SCALER_CROPPING_TYPE_FREEFORM + */ + public static final Key<Integer> SCALER_CROPPING_TYPE = + new Key<Integer>("android.scaler.croppingType", int.class); + + /** * <p>Area of raw data which corresponds to only * active pixels.</p> * <p>It is smaller or equal to @@ -1324,19 +1496,6 @@ public final class CameraCharacteristics extends CameraMetadata { new Key<Rational[]>("android.sensor.forwardMatrix2", Rational[].class); /** - * <p>Gain factor from electrons to raw units when - * ISO=100</p> - * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> - * <p><b>Full capability</b> - - * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the - * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p> - * - * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL - */ - public static final Key<Rational> SENSOR_BASE_GAIN_FACTOR = - new Key<Rational>("android.sensor.baseGainFactor", Rational.class); - - /** * <p>A fixed black level offset for each of the color filter arrangement * (CFA) mosaic channels.</p> * <p>This tag specifies the zero light value for each of the CFA mosaic diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index ca03dae..77640d1 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -242,10 +242,126 @@ public interface CameraDevice extends AutoCloseable { * @see StreamConfigurationMap#getOutputFormats() * @see StreamConfigurationMap#getOutputSizes(int) * @see StreamConfigurationMap#getOutputSizes(Class) + * @deprecated Use {@link #createCaptureSession} instead */ public void configureOutputs(List<Surface> outputs) throws CameraAccessException; /** + * <p>Create a new camera capture session by providing the target output set of Surfaces to the + * camera device.</p> + * + * <p>The active capture session determines the set of potential output Surfaces for + * the camera device for each capture request. A given request may use all + * or a only some of the outputs. Once the CameraCaptureSession is created, requests can be + * can be submitted with {@link CameraCaptureSession#capture capture}, + * {@link CameraCaptureSession#captureBurst captureBurst}, + * {@link CameraCaptureSession#setRepeatingRequest setRepeatingRequest}, or + * {@link CameraCaptureSession#setRepeatingBurst setRepeatingBurst}.</p> + * + * <p>Surfaces suitable for inclusion as a camera output can be created for + * various use cases and targets:</p> + * + * <ul> + * + * <li>For drawing to a {@link android.view.SurfaceView SurfaceView}: Set the size of the + * Surface with {@link android.view.SurfaceHolder#setFixedSize} to be one of the sizes + * returned by + * {@link StreamConfigurationMap#getOutputSizes(Class) getOutputSizes(SurfaceView.class)} + * and then obtain the Surface by calling {@link android.view.SurfaceHolder#getSurface}.</li> + * + * <li>For accessing through an OpenGL texture via a + * {@link android.graphics.SurfaceTexture SurfaceTexture}: Set the size of + * the SurfaceTexture with + * {@link android.graphics.SurfaceTexture#setDefaultBufferSize} to be one + * of the sizes returned by + * {@link StreamConfigurationMap#getOutputSizes(Class) getOutputSizes(SurfaceTexture.class)} + * before creating a Surface from the SurfaceTexture with + * {@link Surface#Surface}.</li> + * + * <li>For recording with {@link android.media.MediaCodec}: Call + * {@link android.media.MediaCodec#createInputSurface} after configuring + * the media codec to use one of the sizes returned by + * {@link StreamConfigurationMap#getOutputSizes(Class) getOutputSizes(MediaCodec.class)} + * </li> + * + * <li>For recording with {@link android.media.MediaRecorder}: Call + * {@link android.media.MediaRecorder#getSurface} after configuring the media recorder to use + * one of the sizes returned by + * {@link StreamConfigurationMap#getOutputSizes(Class) getOutputSizes(MediaRecorder.class)}, + * or configuring it to use one of the supported + * {@link android.media.CamcorderProfile CamcorderProfiles}.</li> + * + * <li>For efficient YUV processing with {@link android.renderscript}: + * Create a RenderScript + * {@link android.renderscript.Allocation Allocation} with a supported YUV + * type, the IO_INPUT flag, and one of the sizes returned by + * {@link StreamConfigurationMap#getOutputSizes(Class) getOutputSizes(Allocation.class)}, + * Then obtain the Surface with + * {@link android.renderscript.Allocation#getSurface}.</li> + * + * <li>For access to raw, uncompressed or JPEG data in the application: Create a + * {@link android.media.ImageReader} object with the one of the supported + * {@link StreamConfigurationMap#getOutputFormats() output image formats}, and a + * size from the supported + * {@link StreamConfigurationMap#getOutputSizes(int) sizes for that format}. Then obtain + * a Surface from it with {@link android.media.ImageReader#getSurface}.</li> + * + * </ul> + * + * </p> + * + * <p>The camera device will query each Surface's size and formats upon this + * call, so they must be set to a valid setting at this time (in particular: + * if the format is user-visible, it must be one of + * {@link StreamConfigurationMap#getOutputFormats}; and the size must be one of + * {@link StreamConfigurationMap#getOutputSizes(int)}).</p> + * + * <p>It can take several hundred milliseconds for the session's configuration to complete, + * since camera hardware may need to be powered on or reconfigured. Once the configuration is + * complete and the session is ready to actually capture data, the provided + * {@link CameraCaptureSession.StateListener}'s + * {@link CameraCaptureSession.StateListener#onConfigured} callback will be called.</p> + * + * <p>If a prior CameraCaptureSession already exists when a new one is created, the previous + * session is closed. Any in-progress capture requests made on the prior session will be + * completed before the new session is configured and is able to start capturing its own + * requests. To minimize the transition time, the {@link CameraCaptureSession#abortCaptures} + * call can be used to discard the remaining requests for the prior capture session before a new + * one is created. Note that once the new session is created, the old one can no longer have its + * captures aborted.</p> + * + * <p>Using larger resolution outputs, or more outputs, can result in slower + * output rate from the device.</p> + * + * <p>Configuring a session with an empty or null list will close the current session, if + * any. This can be used to release the current session's target surfaces for another use.</p> + * + * @param outputs The new set of Surfaces that should be made available as + * targets for captured image data. + * @param listener The listener to notify about the status of the new capture session. + * @param handler The handler on which the listener should be invoked, or {@code null} to use + * the current thread's {@link android.os.Looper looper}. + * <!-- + * @return A new camera capture session to use, or null if an empty/null set of Surfaces is + * provided. + * --> + * @throws IllegalArgumentException if the set of output Surfaces do not meet the requirements, + * the listener is null, or the handler is null but the current + * thread has no looper. + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if the camera device has been closed + * + * @see CameraCaptureSession + * @see StreamConfigurationMap#getOutputFormats() + * @see StreamConfigurationMap#getOutputSizes(int) + * @see StreamConfigurationMap#getOutputSizes(Class) + */ + public void createCaptureSession(List<Surface> outputs, + CameraCaptureSession.StateListener listener, Handler handler) + throws CameraAccessException; + + /** * <p>Create a {@link CaptureRequest.Builder} for new capture requests, * initialized with template for a target use case. The settings are chosen * to be the best options for the specific camera device, so it is not @@ -314,6 +430,7 @@ public interface CameraDevice extends AutoCloseable { * @see #captureBurst * @see #setRepeatingRequest * @see #setRepeatingBurst + * @deprecated Use {@link CameraCaptureSession} instead */ public int capture(CaptureRequest request, CaptureListener listener, Handler handler) throws CameraAccessException; @@ -358,6 +475,7 @@ public interface CameraDevice extends AutoCloseable { * @see #capture * @see #setRepeatingRequest * @see #setRepeatingBurst + * @deprecated Use {@link CameraCaptureSession} instead */ public int captureBurst(List<CaptureRequest> requests, CaptureListener listener, Handler handler) throws CameraAccessException; @@ -416,6 +534,7 @@ public interface CameraDevice extends AutoCloseable { * @see #setRepeatingBurst * @see #stopRepeating * @see #flush + * @deprecated Use {@link CameraCaptureSession} instead */ public int setRepeatingRequest(CaptureRequest request, CaptureListener listener, Handler handler) throws CameraAccessException; @@ -474,6 +593,7 @@ public interface CameraDevice extends AutoCloseable { * @see #setRepeatingRequest * @see #stopRepeating * @see #flush + * @deprecated Use {@link CameraCaptureSession} instead */ public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener, Handler handler) throws CameraAccessException; @@ -498,6 +618,7 @@ public interface CameraDevice extends AutoCloseable { * @see #setRepeatingRequest * @see #setRepeatingBurst * @see StateListener#onIdle + * @deprecated Use {@link CameraCaptureSession} instead */ public void stopRepeating() throws CameraAccessException; @@ -534,25 +655,24 @@ public interface CameraDevice extends AutoCloseable { * @see #setRepeatingRequest * @see #setRepeatingBurst * @see #configureOutputs + * @deprecated Use {@link CameraCaptureSession} instead */ public void flush() throws CameraAccessException; /** - * Close the connection to this camera device. + * Close the connection to this camera device as quickly as possible. * - * <p>After this call, all calls to - * the camera device interface will throw a {@link IllegalStateException}, - * except for calls to close(). Once the device has fully shut down, the - * {@link StateListener#onClosed} callback will be called, and the camera is - * free to be re-opened.</p> + * <p>Immediately after this call, all calls to the camera device or active session interface + * will throw a {@link IllegalStateException}, except for calls to close(). Once the device has + * fully shut down, the {@link StateListener#onClosed} callback will be called, and the camera + * is free to be re-opened.</p> * - * <p>After this call, besides the final {@link StateListener#onClosed} call, no calls to the - * device's {@link StateListener} will occur, and any remaining submitted capture requests will - * not fire their {@link CaptureListener} callbacks.</p> + * <p>Immediately after this call, besides the final {@link StateListener#onClosed} calls, no + * further callbacks from the device or the active session will occur, and any remaining + * submitted capture requests will be discarded, as if + * {@link CameraCaptureSession#abortCaptures} had been called, except that no success or failure + * callbacks will be invoked.</p> * - * <p>To shut down as fast as possible, call the {@link #flush} method and then {@link #close} - * once the flush completes. This will discard some capture requests, but results in faster - * shutdown.</p> */ @Override public void close(); @@ -569,6 +689,7 @@ public interface CameraDevice extends AutoCloseable { * @see #captureBurst * @see #setRepeatingRequest * @see #setRepeatingBurst + * @deprecated Use {@link CameraCaptureSession} instead */ public static abstract class CaptureListener { @@ -834,6 +955,7 @@ public interface CameraDevice extends AutoCloseable { * <p>The default implementation of this method does nothing.</p> * * @param camera the camera device has that become unconfigured + * @deprecated Use {@link CameraCaptureSession.StateListener} instead. */ public void onUnconfigured(CameraDevice camera) { // Default empty implementation @@ -863,6 +985,7 @@ public interface CameraDevice extends AutoCloseable { * @see CameraDevice#captureBurst * @see CameraDevice#setRepeatingBurst * @see CameraDevice#setRepeatingRequest + * @deprecated Use {@link CameraCaptureSession.StateListener} instead. */ public void onActive(CameraDevice camera) { // Default empty implementation @@ -896,6 +1019,7 @@ public interface CameraDevice extends AutoCloseable { * * @see CameraDevice#configureOutputs * @see CameraDevice#flush + * @deprecated Use {@link CameraCaptureSession.StateListener} instead. */ public void onBusy(CameraDevice camera) { // Default empty implementation @@ -943,6 +1067,7 @@ public interface CameraDevice extends AutoCloseable { * @see CameraDevice#configureOutputs * @see CameraDevice#stopRepeating * @see CameraDevice#flush + * @deprecated Use {@link CameraCaptureSession.StateListener} instead. */ public void onIdle(CameraDevice camera) { // Default empty implementation diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index cb463a6..03b342c 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -199,11 +199,7 @@ public final class CameraManager { } /** - * Open a connection to a camera with the given ID. Use - * {@link #getCameraIdList} to get the list of available camera - * devices. Note that even if an id is listed, open may fail if the device - * is disconnected between the calls to {@link #getCameraIdList} and - * {@link #openCamera}. + * Helper for openning a connection to a camera with the given ID. * * @param cameraId The unique identifier of the camera device to open * @param listener The listener for the camera. Must not be null. @@ -216,20 +212,22 @@ public final class CameraManager { * @throws SecurityException if the application does not have permission to * access the camera * @throws IllegalArgumentException if listener or handler is null. + * @return A handle to the newly-created camera device. * * @see #getCameraIdList * @see android.app.admin.DevicePolicyManager#setCameraDisabled */ - private void openCameraDeviceUserAsync(String cameraId, + private CameraDevice openCameraDeviceUserAsync(String cameraId, CameraDevice.StateListener listener, Handler handler) throws CameraAccessException { + CameraDevice device = null; try { synchronized (mLock) { ICameraDeviceUser cameraUser; - android.hardware.camera2.impl.CameraDevice device = + android.hardware.camera2.impl.CameraDevice deviceImpl = new android.hardware.camera2.impl.CameraDevice( cameraId, listener, @@ -237,7 +235,7 @@ public final class CameraManager { BinderHolder holder = new BinderHolder(); - ICameraDeviceCallbacks callbacks = device.getCallbacks(); + ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks(); int id = Integer.parseInt(cameraId); try { mCameraService.connectDevice(callbacks, id, mContext.getPackageName(), @@ -257,7 +255,8 @@ public final class CameraManager { // TODO: factor out listener to be non-nested, then move setter to constructor // For now, calling setRemoteDevice will fire initial // onOpened/onUnconfigured callbacks. - device.setRemoteDevice(cameraUser); + deviceImpl.setRemoteDevice(cameraUser); + device = deviceImpl; } } catch (NumberFormatException e) { @@ -268,6 +267,7 @@ public final class CameraManager { } catch (RemoteException e) { // impossible } + return device; } /** @@ -278,20 +278,26 @@ public final class CameraManager { * is disconnected between the calls to {@link #getCameraIdList} and * {@link #openCamera}.</p> * - * <p>If the camera successfully opens after this function call returns, - * {@link CameraDevice.StateListener#onOpened} will be invoked with the - * newly opened {@link CameraDevice} in the unconfigured state.</p> + * <p>Once the camera is successfully opened, {@link CameraDevice.StateListener#onOpened} will + * be invoked with the newly opened {@link CameraDevice}. The camera device can then be set up + * for operation by calling {@link CameraDevice#createCaptureSession} and + * {@link CameraDevice#createCaptureRequest}</p> * + * <!-- + * <p>Since the camera device will be opened asynchronously, any asynchronous operations done + * on the returned CameraDevice instance will be queued up until the device startup has + * completed and the listener's {@link CameraDevice.StateListener#onOpened onOpened} method is + * called. The pending operations are then processed in order.</p> + * --> * <p>If the camera becomes disconnected during initialization * after this function call returns, * {@link CameraDevice.StateListener#onDisconnected} with a * {@link CameraDevice} in the disconnected state (and * {@link CameraDevice.StateListener#onOpened} will be skipped).</p> * - * <p>If the camera fails to initialize after this function call returns, - * {@link CameraDevice.StateListener#onError} will be invoked with a - * {@link CameraDevice} in the error state (and - * {@link CameraDevice.StateListener#onOpened} will be skipped).</p> + * <p>If opening the camera device fails, then the device listener's + * {@link CameraDevice.StateListener#onError onError} method will be called, and subsequent + * calls on the camera device will throw an {@link IllegalStateException}.</p> * * @param cameraId * The unique identifier of the camera device to open diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index a11390d..4cde601 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -16,8 +16,7 @@ package android.hardware.camera2; -import android.hardware.camera2.impl.CameraMetadataNative; -import android.hardware.camera2.utils.TypeReference; +import android.util.Log; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -36,7 +35,7 @@ import java.util.List; * * <p> * All instances of CameraMetadata are immutable. The list of keys with {@link #getKeys()} - * never changes, nor do the values returned by any key with {@link #get} throughout + * never changes, nor do the values returned by any key with {@code #get} throughout * the lifetime of the object. * </p> * @@ -44,7 +43,10 @@ import java.util.List; * @see CameraManager * @see CameraCharacteristics **/ -public abstract class CameraMetadata { +public abstract class CameraMetadata<TKey> { + + private static final String TAG = "CameraMetadataAb"; + private static final boolean VERBOSE = false; /** * Set a camera metadata field to a value. The field definitions can be @@ -74,8 +76,15 @@ public abstract class CameraMetadata { * * @param key The metadata field to read. * @return The value of that key, or {@code null} if the field is not set. + * + * @hide */ - public abstract <T> T get(Key<T> key); + protected abstract <T> T getProtected(TKey key); + + /** + * @hide + */ + protected abstract Class<TKey> getKeyClass(); /** * Returns a list of the keys contained in this map. @@ -83,14 +92,16 @@ public abstract class CameraMetadata { * <p>The list returned is not modifiable, so any attempts to modify it will throw * a {@code UnsupportedOperationException}.</p> * - * <p>All values retrieved by a key from this list with {@link #get} are guaranteed to be + * <p>All values retrieved by a key from this list with {@code #get} are guaranteed to be * non-{@code null}. Each key is only listed once in the list. The order of the keys * is undefined.</p> * * @return List of the keys contained in this map. */ - public List<Key<?>> getKeys() { - return Collections.unmodifiableList(getKeysStatic(this.getClass(), this)); + @SuppressWarnings("unchecked") + public List<TKey> getKeys() { + Class<CameraMetadata<TKey>> thisClass = (Class<CameraMetadata<TKey>>) getClass(); + return Collections.unmodifiableList(getKeysStatic(thisClass, getKeyClass(), this)); } /** @@ -101,24 +112,31 @@ public abstract class CameraMetadata { * Optionally, if {@code instance} is not null, then filter out any keys with null values. * </p> */ - /*package*/ static ArrayList<Key<?>> getKeysStatic(Class<? extends CameraMetadata> type, - CameraMetadata instance) { - ArrayList<Key<?>> keyList = new ArrayList<Key<?>>(); + /*package*/ @SuppressWarnings("unchecked") + static <TKey> ArrayList<TKey> getKeysStatic( + Class<?> type, Class<TKey> keyClass, + CameraMetadata<TKey> instance) { + + if (VERBOSE) Log.v(TAG, "getKeysStatic for " + type); + + ArrayList<TKey> keyList = new ArrayList<TKey>(); Field[] fields = type.getDeclaredFields(); for (Field field : fields) { // Filter for Keys that are public - if (field.getType().isAssignableFrom(Key.class) && + if (field.getType().isAssignableFrom(keyClass) && (field.getModifiers() & Modifier.PUBLIC) != 0) { - Key<?> key; + + TKey key; try { - key = (Key<?>) field.get(instance); + key = (TKey) field.get(instance); } catch (IllegalAccessException e) { throw new AssertionError("Can't get IllegalAccessException", e); } catch (IllegalArgumentException e) { throw new AssertionError("Can't get IllegalArgumentException", e); } - if (instance == null || instance.get(key) != null) { + + if (instance == null || instance.getProtected(key) != null) { keyList.add(key); } } @@ -127,113 +145,6 @@ public abstract class CameraMetadata { return keyList; } - // TODO: make final or abstract - public static class Key<T> { - - private boolean mHasTag; - private int mTag; - private final Class<T> mType; - private final TypeReference<T> mTypeReference; - private final String mName; - - /** - * @hide - */ - public Key(String name, Class<T> type) { - if (name == null) { - throw new NullPointerException("Key needs a valid name"); - } else if (type == null) { - throw new NullPointerException("Type needs to be non-null"); - } - mName = name; - mType = type; - mTypeReference = TypeReference.createSpecializedTypeReference(type); - } - - /** - * @hide - */ - @SuppressWarnings("unchecked") - public Key(String name, TypeReference<T> typeReference) { - if (name == null) { - throw new NullPointerException("Key needs a valid name"); - } else if (typeReference == null) { - throw new NullPointerException("TypeReference needs to be non-null"); - } - mName = name; - mType = (Class<T>)typeReference.getRawType(); - mTypeReference = typeReference; - } - - public final String getName() { - return mName; - } - - @Override - public final int hashCode() { - return mName.hashCode() ^ mTypeReference.hashCode(); - } - - @Override - public final boolean equals(Object o) { - if (this == o) { - return true; - } - - if (!(o instanceof Key)) { - return false; - } - - Key<?> lhs = (Key<?>)o; - return mName.equals(lhs.mName) && mTypeReference.equals(lhs.mTypeReference); - } - - /** - * <p> - * Get the tag corresponding to this key. This enables insertion into the - * native metadata. - * </p> - * - * <p>This value is looked up the first time, and cached subsequently.</p> - * - * @return The tag numeric value corresponding to the string - * - * @hide - */ - public final int getTag() { - if (!mHasTag) { - mTag = CameraMetadataNative.getTag(mName); - mHasTag = true; - } - return mTag; - } - - /** - * Get the raw class backing the type {@code T} for this key. - * - * <p>The distinction is only important if {@code T} is a generic, e.g. - * {@code Range<Integer>} since the nested type will be erased.</p> - * - * @hide - */ - public final Class<T> getType() { - // TODO: remove this; other places should use #getTypeReference() instead - return mType; - } - - /** - * Get the type reference backing the type {@code T} for this key. - * - * <p>The distinction is only important if {@code T} is a generic, e.g. - * {@code Range<Integer>} since the nested type will be retained.</p> - * - * @hide - */ - public final TypeReference<T> getTypeReference() { - return mTypeReference; - } - } - /*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~ * The enum values below this point are generated from metadata * definitions in /system/media/camera/docs. Do not modify by hand or @@ -336,7 +247,6 @@ public abstract class CameraMetadata { * <li>Manual sensitivity control<ul> * <li>{@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}</li> * <li>{@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange}</li> - * <li>{@link CameraCharacteristics#SENSOR_BASE_GAIN_FACTOR android.sensor.baseGainFactor}</li> * </ul> * </li> * <li>Manual lens control<ul> @@ -357,7 +267,6 @@ public abstract class CameraMetadata { * result.</p> * * @see CaptureRequest#BLACK_LEVEL_LOCK - * @see CameraCharacteristics#SENSOR_BASE_GAIN_FACTOR * @see CaptureRequest#SENSOR_EXPOSURE_TIME * @see CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE * @see CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE @@ -446,6 +355,22 @@ public abstract class CameraMetadata { public static final int REQUEST_AVAILABLE_CAPABILITIES_DNG = 5; // + // Enumeration values for CameraCharacteristics#SCALER_CROPPING_TYPE + // + + /** + * <p>The camera device will only support centered crop regions.</p> + * @see CameraCharacteristics#SCALER_CROPPING_TYPE + */ + public static final int SCALER_CROPPING_TYPE_CENTER_ONLY = 0; + + /** + * <p>The camera device will support arbitrarily chosen crop regions.</p> + * @see CameraCharacteristics#SCALER_CROPPING_TYPE + */ + public static final int SCALER_CROPPING_TYPE_FREEFORM = 1; + + // // Enumeration values for CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT // @@ -1365,8 +1290,7 @@ public abstract class CameraMetadata { /** * <p>If the flash is available and charged, fire flash - * for this capture based on android.flash.firingPower and - * android.flash.firingTime.</p> + * for this capture.</p> * @see CaptureRequest#FLASH_MODE */ public static final int FLASH_MODE_SINGLE = 1; diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 54ffd6b..a4aa296 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -16,7 +16,9 @@ package android.hardware.camera2; +import android.hardware.camera2.CameraCharacteristics.Key; import android.hardware.camera2.impl.CameraMetadataNative; +import android.hardware.camera2.utils.TypeReference; import android.os.Parcel; import android.os.Parcelable; import android.util.Rational; @@ -25,6 +27,7 @@ import android.view.Surface; import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Objects; @@ -58,7 +61,98 @@ import java.util.Objects; * @see CameraDevice#setRepeatingRequest * @see CameraDevice#createCaptureRequest */ -public final class CaptureRequest extends CameraMetadata implements Parcelable { +public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> + implements Parcelable { + + /** + * A {@code Key} is used to do capture request field lookups with + * {@link CaptureResult#get} or to set fields with + * {@link CaptureRequest.Builder#set(Key, Object)}. + * + * <p>For example, to set the crop rectangle for the next capture: + * <code><pre> + * Rect cropRectangle = new Rect(0, 0, 640, 480); + * captureRequestBuilder.set(SCALER_CROP_REGION, cropRectangle); + * </pre></code> + * </p> + * + * <p>To enumerate over all possible keys for {@link CaptureResult}, see + * {@link CameraCharacteristics#getAvailableCaptureResultKeys}.</p> + * + * @see CaptureResult#get + * @see CameraCharacteristics#getAvailableCaptureResultKeys + */ + public final static class Key<T> { + private final CameraMetadataNative.Key<T> mKey; + + /** + * Visible for testing and vendor extensions only. + * + * @hide + */ + public Key(String name, Class<T> type) { + mKey = new CameraMetadataNative.Key<T>(name, type); + } + + /** + * Visible for testing and vendor extensions only. + * + * @hide + */ + public Key(String name, TypeReference<T> typeReference) { + mKey = new CameraMetadataNative.Key<T>(name, typeReference); + } + + /** + * Return a camelCase, period separated name formatted like: + * {@code "root.section[.subsections].name"}. + * + * <p>Built-in keys exposed by the Android SDK are always prefixed with {@code "android."}; + * keys that are device/platform-specific are prefixed with {@code "com."}.</p> + * + * <p>For example, {@code CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP} would + * have a name of {@code "android.scaler.streamConfigurationMap"}; whereas a device + * specific key might look like {@code "com.google.nexus.data.private"}.</p> + * + * @return String representation of the key name + */ + public String getName() { + return mKey.getName(); + } + + /** + * {@inheritDoc} + */ + @Override + public final int hashCode() { + return mKey.hashCode(); + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings("unchecked") + @Override + public final boolean equals(Object o) { + return o instanceof Key && ((Key<T>)o).mKey.equals(mKey); + } + + /** + * Visible for CameraMetadataNative implementation only; do not use. + * + * TODO: Make this private or remove it altogether. + * + * @hide + */ + public CameraMetadataNative.Key<T> getNativeKey() { + return mKey; + } + + @SuppressWarnings({ "unchecked" }) + /*package*/ Key(CameraMetadataNative.Key<?> nativeKey) { + mKey = (CameraMetadataNative.Key<T>) nativeKey; + } + } private final HashSet<Surface> mSurfaceSet; private final CameraMetadataNative mSettings; @@ -93,17 +187,58 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * Used by the Builder to create a mutable CaptureRequest. */ private CaptureRequest(CameraMetadataNative settings) { - mSettings = settings; + mSettings = CameraMetadataNative.move(settings); mSurfaceSet = new HashSet<Surface>(); } - @SuppressWarnings("unchecked") - @Override + /** + * Get a capture request field value. + * + * <p>The field definitions can be found in {@link CaptureRequest}.</p> + * + * <p>Querying the value for the same key more than once will return a value + * which is equal to the previous queried value.</p> + * + * @throws IllegalArgumentException if the key was not valid + * + * @param key The result field to read. + * @return The value of that key, or {@code null} if the field is not set. + */ public <T> T get(Key<T> key) { return mSettings.get(key); } /** + * {@inheritDoc} + * @hide + */ + @SuppressWarnings("unchecked") + @Override + protected <T> T getProtected(Key<?> key) { + return (T) mSettings.get(key); + } + + /** + * {@inheritDoc} + * @hide + */ + @SuppressWarnings("unchecked") + @Override + protected Class<Key<?>> getKeyClass() { + Object thisClass = Key.class; + return (Class<Key<?>>)thisClass; + } + + /** + * {@inheritDoc} + */ + @Override + public List<Key<?>> getKeys() { + // Force the javadoc for this function to show up on the CaptureRequest page + return super.getKeys(); + } + + /** * Retrieve the tag for this request, if any. * * <p>This tag is not used for anything by the camera device, but can be @@ -569,9 +704,9 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * should be nonnegative.</p> * <p>If all regions have 0 weight, then no specific metering area * needs to be used by the camera device. If the metering region is - * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the camera device - * will ignore the sections outside the region and output the - * used sections in the frame metadata.</p> + * outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata, + * the camera device will ignore the sections outside the region and output the + * used sections in the result metadata.</p> * * @see CaptureRequest#SCALER_CROP_REGION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE @@ -644,9 +779,9 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * should be nonnegative.</p> * <p>If all regions have 0 weight, then no specific focus area * needs to be used by the camera device. If the focusing region is - * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the camera device - * will ignore the sections outside the region and output the - * used sections in the frame metadata.</p> + * outside the the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture + * result metadata, the camera device will ignore the sections outside + * the region and output the used sections in the result metadata.</p> * * @see CaptureRequest#SCALER_CROP_REGION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE @@ -731,9 +866,9 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * should be nonnegative.</p> * <p>If all regions have 0 weight, then no specific auto-white balance (AWB) area * needs to be used by the camera device. If the AWB region is - * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the camera device - * will ignore the sections outside the region and output the - * used sections in the frame metadata.</p> + * outside the the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata, + * the camera device will ignore the sections outside the region and output the + * used sections in the result metadata.</p> * * @see CaptureRequest#SCALER_CROP_REGION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE @@ -1126,8 +1261,11 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * output, cropping to a smaller region if necessary to * maintain the stream's aspect ratio.</p> * <p>HAL2.x uses only (x, y, width)</p> - * <p>Any additional per-stream cropping must be done to - * maximize the final pixel area of the stream.</p> + * <p>The crop region is applied after the RAW to other color space (e.g. YUV) + * conversion. Since raw streams (e.g. RAW16) don't have the conversion stage, + * it is not croppable. The crop region will be ignored by raw streams.</p> + * <p>For non-raw streams, any additional per-stream cropping will + * be done to maximize the final pixel area of the stream.</p> * <p>For example, if the crop region is set to a 4:3 aspect * ratio, then 4:3 streams should use the exact crop * region. 16:9 streams should further crop vertically @@ -1308,8 +1446,16 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * camera device. Applications can request lens shading map data by setting * {@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE android.statistics.lensShadingMapMode} to ON, and then the camera device will provide * lens shading map data in {@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap}, with size specified - * by {@link CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE android.lens.info.shadingMapSize}.</p> + * by {@link CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE android.lens.info.shadingMapSize}; the returned shading map data will be the one + * applied by the camera device for this capture request.</p> + * <p>The shading map data may depend on the AE and AWB statistics, therefore the reliability + * of the map data may be affected by the AE and AWB algorithms. When AE and AWB are in + * AUTO modes({@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} <code>!=</code> OFF and {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} <code>!=</code> OFF), + * to get best results, it is recommended that the applications wait for the AE and AWB to + * be converged before using the returned shading map data.</p> * + * @see CaptureRequest#CONTROL_AE_MODE + * @see CaptureRequest#CONTROL_AWB_MODE * @see CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE * @see CaptureResult#STATISTICS_LENS_SHADING_MAP * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE @@ -1458,7 +1604,7 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * {@link CaptureRequest#TONEMAP_CURVE_GREEN android.tonemap.curveGreen}, and {@link CaptureRequest#TONEMAP_CURVE_BLUE android.tonemap.curveBlue}. * These values are always available, and as close as possible to the * actually used nonlinear/nonglobal transforms.</p> - * <p>If a request is sent with TRANSFORM_MATRIX with the camera device's + * <p>If a request is sent with CONTRAST_CURVE with the camera device's * provided curve in FAST or HIGH_QUALITY, the image's tonemap will be * roughly the same.</p> * diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index f91fcb9..61d491b 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -17,9 +17,12 @@ package android.hardware.camera2; import android.hardware.camera2.impl.CameraMetadataNative; -import android.hardware.camera2.params.Face; +import android.hardware.camera2.utils.TypeReference; +import android.util.Log; import android.util.Rational; +import java.util.List; + /** * <p>The results of a single image capture from the image sensor.</p> * @@ -36,7 +39,98 @@ import android.util.Rational; * <p>{@link CameraCharacteristics} objects are immutable.</p> * */ -public final class CaptureResult extends CameraMetadata { +public final class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { + + private static final String TAG = "CaptureResult"; + private static final boolean VERBOSE = false; + + /** + * A {@code Key} is used to do capture result field lookups with + * {@link CaptureResult#get}. + * + * <p>For example, to get the timestamp corresponding to the exposure of the first row: + * <code><pre> + * long timestamp = captureResult.get(CaptureResult.SENSOR_TIMESTAMP); + * </pre></code> + * </p> + * + * <p>To enumerate over all possible keys for {@link CaptureResult}, see + * {@link CameraCharacteristics#getAvailableCaptureResultKeys}.</p> + * + * @see CaptureResult#get + * @see CameraCharacteristics#getAvailableCaptureResultKeys + */ + public final static class Key<T> { + private final CameraMetadataNative.Key<T> mKey; + + /** + * Visible for testing and vendor extensions only. + * + * @hide + */ + public Key(String name, Class<T> type) { + mKey = new CameraMetadataNative.Key<T>(name, type); + } + + /** + * Visible for testing and vendor extensions only. + * + * @hide + */ + public Key(String name, TypeReference<T> typeReference) { + mKey = new CameraMetadataNative.Key<T>(name, typeReference); + } + + /** + * Return a camelCase, period separated name formatted like: + * {@code "root.section[.subsections].name"}. + * + * <p>Built-in keys exposed by the Android SDK are always prefixed with {@code "android."}; + * keys that are device/platform-specific are prefixed with {@code "com."}.</p> + * + * <p>For example, {@code CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP} would + * have a name of {@code "android.scaler.streamConfigurationMap"}; whereas a device + * specific key might look like {@code "com.google.nexus.data.private"}.</p> + * + * @return String representation of the key name + */ + public String getName() { + return mKey.getName(); + } + + /** + * {@inheritDoc} + */ + @Override + public final int hashCode() { + return mKey.hashCode(); + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings("unchecked") + @Override + public final boolean equals(Object o) { + return o instanceof Key && ((Key<T>)o).mKey.equals(mKey); + } + + /** + * Visible for CameraMetadataNative implementation only; do not use. + * + * TODO: Make this private or remove it altogether. + * + * @hide + */ + public CameraMetadataNative.Key<T> getNativeKey() { + return mKey; + } + + @SuppressWarnings({ "unchecked" }) + /*package*/ Key(CameraMetadataNative.Key<?> nativeKey) { + mKey = (CameraMetadataNative.Key<T>) nativeKey; + } + } private final CameraMetadataNative mResults; private final CaptureRequest mRequest; @@ -55,7 +149,10 @@ public final class CaptureResult extends CameraMetadata { throw new IllegalArgumentException("parent was null"); } - mResults = results; + mResults = CameraMetadataNative.move(results); + if (mResults.isEmpty()) { + throw new AssertionError("Results must not be empty"); + } mRequest = parent; mSequenceId = sequenceId; } @@ -68,9 +165,85 @@ public final class CaptureResult extends CameraMetadata { return new CameraMetadataNative(mResults); } - @Override + /** + * Creates a request-less result. + * + * <p><strong>For testing only.</strong></p> + * @hide + */ + public CaptureResult(CameraMetadataNative results, int sequenceId) { + if (results == null) { + throw new IllegalArgumentException("results was null"); + } + + mResults = CameraMetadataNative.move(results); + if (mResults.isEmpty()) { + throw new AssertionError("Results must not be empty"); + } + + mRequest = null; + mSequenceId = sequenceId; + } + + /** + * Get a capture result field value. + * + * <p>The field definitions can be found in {@link CaptureResult}.</p> + * + * <p>Querying the value for the same key more than once will return a value + * which is equal to the previous queried value.</p> + * + * @throws IllegalArgumentException if the key was not valid + * + * @param key The result field to read. + * @return The value of that key, or {@code null} if the field is not set. + */ public <T> T get(Key<T> key) { - return mResults.get(key); + T value = mResults.get(key); + if (VERBOSE) Log.v(TAG, "#get for Key = " + key.getName() + ", returned value = " + value); + return value; + } + + /** + * {@inheritDoc} + * @hide + */ + @SuppressWarnings("unchecked") + @Override + protected <T> T getProtected(Key<?> key) { + return (T) mResults.get(key); + } + + /** + * {@inheritDoc} + * @hide + */ + @SuppressWarnings("unchecked") + @Override + protected Class<Key<?>> getKeyClass() { + Object thisClass = Key.class; + return (Class<Key<?>>)thisClass; + } + + /** + * Dumps the native metadata contents to logcat. + * + * <p>Visibility for testing/debugging only. The results will not + * include any synthesized keys, as they are invisible to the native layer.</p> + * + * @hide + */ + public void dumpToLog() { + mResults.dumpToLog(); + } + + /** + * {@inheritDoc} + */ + @Override + public List<Key<?>> getKeys() { + // Force the javadoc for this function to show up on the CaptureResult page + return super.getKeys(); } /** @@ -110,6 +283,7 @@ public final class CaptureResult extends CameraMetadata { * @return int frame number */ public int getFrameNumber() { + // TODO: @hide REQUEST_FRAME_COUNT return get(REQUEST_FRAME_COUNT); } @@ -369,9 +543,9 @@ public final class CaptureResult extends CameraMetadata { * should be nonnegative.</p> * <p>If all regions have 0 weight, then no specific metering area * needs to be used by the camera device. If the metering region is - * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the camera device - * will ignore the sections outside the region and output the - * used sections in the frame metadata.</p> + * outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata, + * the camera device will ignore the sections outside the region and output the + * used sections in the result metadata.</p> * * @see CaptureRequest#SCALER_CROP_REGION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE @@ -642,9 +816,9 @@ public final class CaptureResult extends CameraMetadata { * should be nonnegative.</p> * <p>If all regions have 0 weight, then no specific focus area * needs to be used by the camera device. If the focusing region is - * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the camera device - * will ignore the sections outside the region and output the - * used sections in the frame metadata.</p> + * outside the the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture + * result metadata, the camera device will ignore the sections outside + * the region and output the used sections in the result metadata.</p> * * @see CaptureRequest#SCALER_CROP_REGION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE @@ -1126,9 +1300,9 @@ public final class CaptureResult extends CameraMetadata { * should be nonnegative.</p> * <p>If all regions have 0 weight, then no specific auto-white balance (AWB) area * needs to be used by the camera device. If the AWB region is - * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the camera device - * will ignore the sections outside the region and output the - * used sections in the frame metadata.</p> + * outside the the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata, + * the camera device will ignore the sections outside the region and output the + * used sections in the result metadata.</p> * * @see CaptureRequest#SCALER_CROP_REGION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE @@ -1749,8 +1923,11 @@ public final class CaptureResult extends CameraMetadata { * output, cropping to a smaller region if necessary to * maintain the stream's aspect ratio.</p> * <p>HAL2.x uses only (x, y, width)</p> - * <p>Any additional per-stream cropping must be done to - * maximize the final pixel area of the stream.</p> + * <p>The crop region is applied after the RAW to other color space (e.g. YUV) + * conversion. Since raw streams (e.g. RAW16) don't have the conversion stage, + * it is not croppable. The crop region will be ignored by raw streams.</p> + * <p>For non-raw streams, any additional per-stream cropping will + * be done to maximize the final pixel area of the stream.</p> * <p>For example, if the crop region is set to a 4:3 aspect * ratio, then 4:3 streams should use the exact crop * region. 16:9 streams should further crop vertically @@ -1885,21 +2062,6 @@ public final class CaptureResult extends CameraMetadata { new Key<Long>("android.sensor.timestamp", long.class); /** - * <p>The temperature of the sensor, sampled at the time - * exposure began for this frame.</p> - * <p>The thermal diode being queried should be inside the sensor PCB, or - * somewhere close to it.</p> - * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> - * <p><b>Full capability</b> - - * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the - * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p> - * - * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL - */ - public static final Key<Float> SENSOR_TEMPERATURE = - new Key<Float>("android.sensor.temperature", float.class); - - /** * <p>The estimated camera neutral color in the native sensor colorspace at * the time of capture.</p> * <p>This value gives the neutral color point encoded as an RGB value in the @@ -2006,8 +2168,16 @@ public final class CaptureResult extends CameraMetadata { * camera device. Applications can request lens shading map data by setting * {@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE android.statistics.lensShadingMapMode} to ON, and then the camera device will provide * lens shading map data in {@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap}, with size specified - * by {@link CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE android.lens.info.shadingMapSize}.</p> + * by {@link CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE android.lens.info.shadingMapSize}; the returned shading map data will be the one + * applied by the camera device for this capture request.</p> + * <p>The shading map data may depend on the AE and AWB statistics, therefore the reliability + * of the map data may be affected by the AE and AWB algorithms. When AE and AWB are in + * AUTO modes({@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} <code>!=</code> OFF and {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} <code>!=</code> OFF), + * to get best results, it is recommended that the applications wait for the AE and AWB to + * be converged before using the returned shading map data.</p> * + * @see CaptureRequest#CONTROL_AE_MODE + * @see CaptureRequest#CONTROL_AWB_MODE * @see CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE * @see CaptureResult#STATISTICS_LENS_SHADING_MAP * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE @@ -2338,7 +2508,7 @@ public final class CaptureResult extends CameraMetadata { * {@link CaptureRequest#TONEMAP_CURVE_GREEN android.tonemap.curveGreen}, and {@link CaptureRequest#TONEMAP_CURVE_BLUE android.tonemap.curveBlue}. * These values are always available, and as close as possible to the * actually used nonlinear/nonglobal transforms.</p> - * <p>If a request is sent with TRANSFORM_MATRIX with the camera device's + * <p>If a request is sent with CONTRAST_CURVE with the camera device's * provided curve in FAST or HIGH_QUALITY, the image's tonemap will be * roughly the same.</p> * diff --git a/media/java/android/media/DngCreator.java b/core/java/android/hardware/camera2/DngCreator.java index 76c6d46..54568ed 100644 --- a/media/java/android/media/DngCreator.java +++ b/core/java/android/hardware/camera2/DngCreator.java @@ -14,14 +14,14 @@ * limitations under the License. */ -package android.media; +package android.hardware.camera2; import android.graphics.Bitmap; import android.graphics.ImageFormat; -import android.hardware.camera2.CameraCharacteristics; -import android.hardware.camera2.CaptureResult; import android.hardware.camera2.impl.CameraMetadataNative; import android.location.Location; +import android.media.ExifInterface; +import android.media.Image; import android.util.Size; import java.io.IOException; @@ -266,6 +266,7 @@ public final class DngCreator implements AutoCloseable { * </p> * * @param dngOutput an {@link java.io.OutputStream} to write the DNG file to. + * @param size the {@link Size} of the image to write, in pixels. * @param pixels an {@link java.nio.ByteBuffer} of pixel data to write. * @param offset the offset of the raw image in bytes. This indicates how many bytes will * be skipped in the input before any pixel data is read. @@ -362,7 +363,6 @@ public final class DngCreator implements AutoCloseable { long offset) throws IOException; static { - System.loadLibrary("media_jni"); nativeClassInit(); } } diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java index e78ffff..b082a70 100644 --- a/core/java/android/hardware/camera2/impl/CameraDevice.java +++ b/core/java/android/hardware/camera2/impl/CameraDevice.java @@ -19,6 +19,7 @@ package android.hardware.camera2.impl; import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE; import android.hardware.camera2.CameraAccessException; +import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.ICameraDeviceCallbacks; @@ -253,6 +254,13 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } @Override + public void createCaptureSession(List<Surface> outputs, + CameraCaptureSession.StateListener listener, Handler handler) + throws CameraAccessException { + // TODO + } + + @Override public CaptureRequest.Builder createCaptureRequest(int templateType) throws CameraAccessException { synchronized (mLock) { diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 27cfd38..ab2c49a 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -20,7 +20,7 @@ import android.graphics.ImageFormat; import android.graphics.Point; import android.graphics.Rect; import android.hardware.camera2.CameraCharacteristics; -import android.hardware.camera2.CameraMetadata; +import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.marshal.Marshaler; import android.hardware.camera2.marshal.MarshalQueryable; @@ -46,10 +46,14 @@ import android.hardware.camera2.params.Face; import android.hardware.camera2.params.StreamConfiguration; import android.hardware.camera2.params.StreamConfigurationDuration; import android.hardware.camera2.params.StreamConfigurationMap; +import android.hardware.camera2.utils.TypeReference; import android.os.Parcelable; import android.os.Parcel; import android.util.Log; +import com.android.internal.util.Preconditions; + +import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; @@ -58,7 +62,147 @@ import java.util.ArrayList; * Implementation of camera metadata marshal/unmarshal across Binder to * the camera service */ -public class CameraMetadataNative extends CameraMetadata implements Parcelable { +public class CameraMetadataNative implements Parcelable { + + public static class Key<T> { + private boolean mHasTag; + private int mTag; + private final Class<T> mType; + private final TypeReference<T> mTypeReference; + private final String mName; + + /** + * Visible for testing only. + * + * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key + * for application code or vendor-extended keys.</p> + */ + public Key(String name, Class<T> type) { + if (name == null) { + throw new NullPointerException("Key needs a valid name"); + } else if (type == null) { + throw new NullPointerException("Type needs to be non-null"); + } + mName = name; + mType = type; + mTypeReference = TypeReference.createSpecializedTypeReference(type); + } + + /** + * Visible for testing only. + * + * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key + * for application code or vendor-extended keys.</p> + */ + @SuppressWarnings("unchecked") + public Key(String name, TypeReference<T> typeReference) { + if (name == null) { + throw new NullPointerException("Key needs a valid name"); + } else if (typeReference == null) { + throw new NullPointerException("TypeReference needs to be non-null"); + } + mName = name; + mType = (Class<T>)typeReference.getRawType(); + mTypeReference = typeReference; + } + + /** + * Return a camelCase, period separated name formatted like: + * {@code "root.section[.subsections].name"}. + * + * <p>Built-in keys exposed by the Android SDK are always prefixed with {@code "android."}; + * keys that are device/platform-specific are prefixed with {@code "com."}.</p> + * + * <p>For example, {@code CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP} would + * have a name of {@code "android.scaler.streamConfigurationMap"}; whereas a device + * specific key might look like {@code "com.google.nexus.data.private"}.</p> + * + * @return String representation of the key name + */ + public final String getName() { + return mName; + } + + /** + * {@inheritDoc} + */ + @Override + public final int hashCode() { + return mName.hashCode() ^ mTypeReference.hashCode(); + } + + /** + * Compare this key against other native keys, request keys, result keys, and + * characteristics keys. + * + * <p>Two keys are considered equal if their name and type reference are equal.</p> + * + * <p>Note that the equality against non-native keys is one-way. A native key may be equal + * to a result key; but that same result key will not be equal to a native key.</p> + */ + @SuppressWarnings("rawtypes") + @Override + public final boolean equals(Object o) { + if (this == o) { + return true; + } + + Key<?> lhs; + + if (o instanceof CaptureResult.Key) { + lhs = ((CaptureResult.Key)o).getNativeKey(); + } else if (o instanceof CaptureRequest.Key) { + lhs = ((CaptureRequest.Key)o).getNativeKey(); + } else if (o instanceof CameraCharacteristics.Key) { + lhs = ((CameraCharacteristics.Key)o).getNativeKey(); + } else if ((o instanceof Key)) { + lhs = (Key<?>)o; + } else { + return false; + } + + return mName.equals(lhs.mName) && mTypeReference.equals(lhs.mTypeReference); + } + + /** + * <p> + * Get the tag corresponding to this key. This enables insertion into the + * native metadata. + * </p> + * + * <p>This value is looked up the first time, and cached subsequently.</p> + * + * @return The tag numeric value corresponding to the string + */ + public final int getTag() { + if (!mHasTag) { + mTag = CameraMetadataNative.getTag(mName); + mHasTag = true; + } + return mTag; + } + + /** + * Get the raw class backing the type {@code T} for this key. + * + * <p>The distinction is only important if {@code T} is a generic, e.g. + * {@code Range<Integer>} since the nested type will be erased.</p> + */ + public final Class<T> getType() { + // TODO: remove this; other places should use #getTypeReference() instead + return mType; + } + + /** + * Get the type reference backing the type {@code T} for this key. + * + * <p>The distinction is only important if {@code T} is a generic, e.g. + * {@code Range<Integer>} since the nested type will be retained.</p> + */ + public final TypeReference<T> getTypeReference() { + return mTypeReference; + } + } private static final String TAG = "CameraMetadataJV"; private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); @@ -84,6 +228,20 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable { } } + /** + * Move the contents from {@code other} into a new camera metadata instance.</p> + * + * <p>After this call, {@code other} will become empty.</p> + * + * @param other the previous metadata instance which will get pilfered + * @return a new metadata instance with the values from {@code other} moved into it + */ + public static CameraMetadataNative move(CameraMetadataNative other) { + CameraMetadataNative newObject = new CameraMetadataNative(); + newObject.swap(other); + return newObject; + } + public static final Parcelable.Creator<CameraMetadataNative> CREATOR = new Parcelable.Creator<CameraMetadataNative>() { @Override @@ -109,8 +267,36 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable { nativeWriteToParcel(dest); } - @Override + /** + * @hide + */ + public <T> T get(CameraCharacteristics.Key<T> key) { + return get(key.getNativeKey()); + } + + /** + * @hide + */ + public <T> T get(CaptureResult.Key<T> key) { + return get(key.getNativeKey()); + } + + /** + * @hide + */ + public <T> T get(CaptureRequest.Key<T> key) { + return get(key.getNativeKey()); + } + + /** + * Look-up a metadata field value by its key. + * + * @param key a non-{@code null} key instance + * @return the field corresponding to the {@code key}, or {@code null} if no value was set + */ public <T> T get(Key<T> key) { + Preconditions.checkNotNull(key, "key must not be null"); + T value = getOverride(key); if (value != null) { return value; @@ -152,6 +338,18 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable { setBase(key, value); } + public <T> void set(CaptureRequest.Key<T> key, T value) { + set(key.getNativeKey(), value); + } + + public <T> void set(CaptureResult.Key<T> key, T value) { + set(key.getNativeKey(), value); + } + + public <T> void set(CameraCharacteristics.Key<T> key, T value) { + set(key.getNativeKey(), value); + } + // Keep up-to-date with camera_metadata.h /** * @hide @@ -188,6 +386,18 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable { mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final } + private <T> T getBase(CameraCharacteristics.Key<T> key) { + return getBase(key.getNativeKey()); + } + + private <T> T getBase(CaptureResult.Key<T> key) { + return getBase(key.getNativeKey()); + } + + private <T> T getBase(CaptureRequest.Key<T> key) { + return getBase(key.getNativeKey()); + } + private <T> T getBase(Key<T> key) { int tag = key.getTag(); byte[] values = readValues(tag); @@ -342,6 +552,18 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable { return new StreamConfigurationMap(configurations, minFrameDurations, stallDurations); } + private <T> void setBase(CameraCharacteristics.Key<T> key, T value) { + setBase(key.getNativeKey(), value); + } + + private <T> void setBase(CaptureResult.Key<T> key, T value) { + setBase(key.getNativeKey(), value); + } + + private <T> void setBase(CaptureRequest.Key<T> key, T value) { + setBase(key.getNativeKey(), value); + } + private <T> void setBase(Key<T> key, T value) { int tag = key.getTag(); @@ -440,6 +662,7 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable { private native synchronized byte[] nativeReadValues(int tag); private native synchronized void nativeWriteValues(int tag, byte[] src); + private native synchronized void nativeDump() throws IOException; // dump to ALOGD private static native int nativeGetTagFromKey(String keyName) throws IllegalArgumentException; @@ -531,6 +754,22 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable { return nativeReadValues(tag); } + /** + * Dumps the native metadata contents to logcat. + * + * <p>Visibility for testing/debugging only. The results will not + * include any synthesized keys, as they are invisible to the native layer.</p> + * + * @hide + */ + public void dumpToLog() { + try { + nativeDump(); + } catch (IOException e) { + Log.wtf(TAG, "Dump logging failed", e); + } + } + @Override protected void finalize() throws Throwable { try { @@ -599,5 +838,4 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable { nativeClassInit(); registerAllMarshalers(); } - } diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java index 71adf8b..22ff9c6 100644 --- a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java +++ b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java @@ -93,7 +93,7 @@ public class CameraDeviceState { * {@link CameraDeviceStateListener#onConfiguring()} will be called. * </p> * - * @returns {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred. + * @return {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred. */ public synchronized int setConfiguring() { doStateTransition(STATE_CONFIGURING); @@ -108,7 +108,7 @@ public class CameraDeviceState { * {@link CameraDeviceStateListener#onIdle()} will be called. * </p> * - * @returns {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred. + * @return {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred. */ public synchronized int setIdle() { doStateTransition(STATE_IDLE); @@ -124,7 +124,7 @@ public class CameraDeviceState { * </p> * * @param request A {@link RequestHolder} containing the request for the current capture. - * @returns {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred. + * @return {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred. */ public synchronized int setCaptureStart(final RequestHolder request) { mCurrentRequest = request; @@ -144,7 +144,7 @@ public class CameraDeviceState { * * @param request the {@link RequestHolder} request that created this result. * @param result the {@link CameraMetadataNative} result to set. - * @returns {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred. + * @return {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred. */ public synchronized int setCaptureResult(final RequestHolder request, final CameraMetadataNative result) { diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 70cc708..5df4baf 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -47,7 +47,7 @@ public class EthernetManager { } /** - * Get Ethernet configuration + * Get Ethernet configuration. * @return the Ethernet Configuration, contained in {@link IpConfiguration}. */ public IpConfiguration getConfiguration() { @@ -61,8 +61,7 @@ public class EthernetManager { } /** - * Set Ethernet configuration - * @return true if setting success + * Set Ethernet configuration. */ public void setConfiguration(IpConfiguration config) { try { diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index af45fa0..d3c6fd5 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -2443,8 +2443,10 @@ public abstract class BatteryStats implements Parcelable { pw.print(prefix); pw.print(" Capacity: "); printmAh(pw, helper.getPowerProfile().getBatteryCapacity()); pw.print(", Computed drain: "); printmAh(pw, helper.getComputedPower()); - pw.print(", Min drain: "); printmAh(pw, helper.getMinDrainedPower()); - pw.print(", Max drain: "); printmAh(pw, helper.getMaxDrainedPower()); + pw.print(", actual drain: "); printmAh(pw, helper.getMinDrainedPower()); + if (helper.getMinDrainedPower() != helper.getMaxDrainedPower()) { + pw.print("-"); printmAh(pw, helper.getMaxDrainedPower()); + } pw.println(); for (int i=0; i<sippers.size(); i++) { BatterySipper bs = sippers.get(i); @@ -3351,7 +3353,10 @@ public abstract class BatteryStats implements Parcelable { } hprinter.printNextItem(pw, rec, baseTime, checkin, (flags&DUMP_VERBOSE) != 0); - } else if (rec.eventCode != HistoryItem.EVENT_NONE) { + } else if (false && rec.eventCode != HistoryItem.EVENT_NONE) { + // This is an attempt to aggregate the previous state and generate + //Â fake events to reflect that state at the point where we start + // printing real events. It doesn't really work right, so is turned off. if (tracker == null) { tracker = new HistoryEventTracker(); } diff --git a/core/java/android/os/CommonBundle.java b/core/java/android/os/CommonBundle.java index e11f170..c1b202c 100644 --- a/core/java/android/os/CommonBundle.java +++ b/core/java/android/os/CommonBundle.java @@ -18,11 +18,10 @@ package android.os; import android.util.ArrayMap; import android.util.Log; -import android.util.SparseArray; import java.io.Serializable; import java.util.ArrayList; -import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -304,6 +303,16 @@ abstract class CommonBundle implements Parcelable, Cloneable { } /** + * Inserts all mappings from the given Map into this CommonBundle. + * + * @param map a Map + */ + void putAll(Map map) { + unparcel(); + mMap.putAll(map); + } + + /** * Returns a Set containing the Strings used as keys in this Bundle. * * @return a Set of String keys diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java index c2cd3be..cd8d515 100644 --- a/core/java/android/os/PersistableBundle.java +++ b/core/java/android/os/PersistableBundle.java @@ -17,7 +17,14 @@ package android.os; import android.util.ArrayMap; - +import com.android.internal.util.XmlUtils; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.IOException; +import java.util.Iterator; +import java.util.Map; import java.util.Set; /** @@ -25,7 +32,8 @@ import java.util.Set; * restored. * */ -public final class PersistableBundle extends CommonBundle { +public final class PersistableBundle extends CommonBundle implements XmlUtils.WriteMapCallback { + private static final String TAG_PERSISTABLEMAP = "pbundle_as_map"; public static final PersistableBundle EMPTY; static final Parcel EMPTY_PARCEL; @@ -88,6 +96,38 @@ public final class PersistableBundle extends CommonBundle { } /** + * Constructs a PersistableBundle containing the mappings passed in. + * + * @param map a Map containing only those items that can be persisted. + * @throws IllegalArgumentException if any element of #map cannot be persisted. + */ + private PersistableBundle(Map<String, Object> map) { + super(); + + // First stuff everything in. + putAll(map); + + // Now verify each item throwing an exception if there is a violation. + Set<String> keys = map.keySet(); + Iterator<String> iterator = keys.iterator(); + while (iterator.hasNext()) { + String key = iterator.next(); + Object value = map.get(key); + if (value instanceof Map) { + // Fix up any Maps by replacing them with PersistableBundles. + putPersistableBundle(key, new PersistableBundle((Map<String, Object>) value)); + } else if (!(value instanceof Integer) && !(value instanceof Long) && + !(value instanceof Double) && !(value instanceof String) && + !(value instanceof int[]) && !(value instanceof long[]) && + !(value instanceof double[]) && !(value instanceof String[]) && + !(value instanceof PersistableBundle) && (value != null)) { + throw new IllegalArgumentException("Bad value in PersistableBundle key=" + key + + " value=" + value); + } + } + } + + /** * Make a PersistableBundle for a single key/value pair. * * @hide @@ -206,6 +246,7 @@ public final class PersistableBundle extends CommonBundle { * * @param bundle a PersistableBundle */ + @Override public void putAll(PersistableBundle bundle) { super.putAll(bundle); } @@ -323,6 +364,7 @@ public final class PersistableBundle extends CommonBundle { * @param key a String, or null * @param value a Bundle object, or null */ + @Override public void putPersistableBundle(String key, PersistableBundle value) { super.putPersistableBundle(key, value); } @@ -539,6 +581,57 @@ public final class PersistableBundle extends CommonBundle { super.readFromParcelInner(parcel); } + /** @hide */ + @Override + public void writeUnknownObject(Object v, String name, XmlSerializer out) + throws XmlPullParserException, IOException { + if (v instanceof PersistableBundle) { + out.startTag(null, TAG_PERSISTABLEMAP); + out.attribute(null, "name", name); + ((PersistableBundle) v).saveToXml(out); + out.endTag(null, TAG_PERSISTABLEMAP); + } else { + throw new XmlPullParserException("Unknown Object o=" + v); + } + } + + /** @hide */ + public void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { + unparcel(); + XmlUtils.writeMapXml(mMap, out, this); + } + + /** @hide */ + static class MyReadMapCallback implements XmlUtils.ReadMapCallback { + @Override + public Object readThisUnknownObjectXml(XmlPullParser in, String tag) + throws XmlPullParserException, IOException { + if (TAG_PERSISTABLEMAP.equals(tag)) { + return restoreFromXml(in); + } + throw new XmlPullParserException("Unknown tag=" + tag); + } + } + + /** + * @hide + */ + public static PersistableBundle restoreFromXml(XmlPullParser in) throws IOException, + XmlPullParserException { + final int outerDepth = in.getDepth(); + final String startTag = in.getName(); + final String[] tagName = new String[1]; + int event; + while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && + (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) { + if (event == XmlPullParser.START_TAG) { + return new PersistableBundle((Map<String, Object>) + XmlUtils.readThisMapXml(in, startTag, tagName, new MyReadMapCallback())); + } + } + return EMPTY; + } + @Override synchronized public String toString() { if (mParcelledData != null) { diff --git a/core/java/android/provider/TvContract.java b/core/java/android/provider/TvContract.java index 5ffffb5..e4f93a8 100644 --- a/core/java/android/provider/TvContract.java +++ b/core/java/android/provider/TvContract.java @@ -462,7 +462,7 @@ public final class TvContract { * <p> * A value of 1 indicates the channel is included in the channel list that applications use * to browse channels, a value of 0 indicates the channel is not included in the list. If - * not specified, this value is set to 1 by default. + * not specified, this value is set to 1 (browsable) by default. * </p><p> * Type: INTEGER (boolean) * </p> @@ -470,6 +470,36 @@ public final class TvContract { public static final String COLUMN_BROWSABLE = "browsable"; /** + * The flag indicating whether this TV channel is searchable or not. + * <p> + * In some regions, it is not allowed to surface search results for a given channel without + * broadcaster's consent. This is used to impose such restriction. A value of 1 indicates + * the channel is searchable and can be included in search results, a value of 0 indicates + * the channel and its TV programs are hidden from search. If not specified, this value is + * set to 1 (searchable) by default. + * </p> + * <p> + * Type: INTEGER (boolean) + * </p> + */ + public static final String COLUMN_SEARCHABLE = "searchable"; + + /** + * The flag indicating whether this TV channel is locked or not. + * <p> + * This is primarily used for alternative parental control to prevent unauthorized users + * from watching the current channel regardless of the content rating. A value of 1 + * indicates the channel is locked and the user is required to enter passcode to unlock it + * in order to watch the current program from the channel, a value of 0 indicates the + * channel is not locked thus the user is not prompted to enter passcode If not specified, + * this value is set to 0 (not locked) by default. + * </p><p> + * Type: INTEGER (boolean) + * </p> + */ + public static final String COLUMN_LOCKED = "locked"; + + /** * Generic data used by individual TV input services. * <p> * Type: BLOB @@ -544,6 +574,33 @@ public final class TvContract { public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis"; /** + * The comma-separated genre string of this TV program. + * <p> + * Use the same language appeared in the underlying broadcast standard, if applicable. (For + * example, one can refer to the genre strings used in Genre Descriptor of ATSC A/65 or + * Content Descriptor of ETSI EN 300 468, if appropriate.) Otherwise, use one of the + * following genres: + * <ul> + * <li>Family/Kids</li> + * <li>Sports</li> + * <li>Shopping</li> + * <li>Movies</li> + * <li>Comedy</li> + * <li>Travel</li> + * <li>Drama</li> + * <li>Education</li> + * <li>Animal/Wildlife</li> + * <li>News</li> + * <li>Gaming</li> + * <li>Others</li> + * </ul> + * </p><p> + * Type: TEXT + * </p> + */ + public static final String COLUMN_GENRE = "genre"; + + /** * The description of this TV program that is displayed to the user by default. * <p> * The maximum length of this field is 256 characters. @@ -566,6 +623,17 @@ public final class TvContract { public static final String COLUMN_LONG_DESCRIPTION = "long_description"; /** + * The comma-separated audio languages of this TV program. + * <p> + * This is used to describe available audio languages included in the program. Use + * 3-character language code as specified by ISO 639-2. + * </p><p> + * Type: TEXT + * </p> + */ + public static final String COLUMN_AUDIO_LANGUAGE = "audio_language"; + + /** * Generic data used by TV input services. * <p> * Type: BLOB diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index a272296..424d860 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -41,10 +41,6 @@ import android.text.TextUtils; * An implementation of Canvas on top of OpenGL ES 2.0. */ class GLES20Canvas extends HardwareCanvas { - // Must match modifiers used in the JNI layer - private static final int MODIFIER_NONE = 0; - private static final int MODIFIER_SHADER = 2; - private final boolean mOpaque; protected long mRenderer; @@ -650,13 +646,8 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) { - int modifiers = setupModifiers(paint, MODIFIER_SHADER); - try { - nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom, - startAngle, sweepAngle, useCenter, paint.mNativePaint); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom, + startAngle, sweepAngle, useCenter, paint.mNativePaint); } private static native void nDrawArc(long renderer, float left, float top, @@ -672,7 +663,6 @@ class GLES20Canvas extends HardwareCanvas { public void drawPatch(NinePatch patch, Rect dst, Paint paint) { Bitmap bitmap = patch.getBitmap(); throwIfCannotDraw(bitmap); - // Shaders are ignored when drawing patches final long nativePaint = paint == null ? 0 : paint.mNativePaint; nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk, dst.left, dst.top, dst.right, dst.bottom, nativePaint); @@ -682,7 +672,6 @@ class GLES20Canvas extends HardwareCanvas { public void drawPatch(NinePatch patch, RectF dst, Paint paint) { Bitmap bitmap = patch.getBitmap(); throwIfCannotDraw(bitmap); - // Shaders are ignored when drawing patches final long nativePaint = paint == null ? 0 : paint.mNativePaint; nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk, dst.left, dst.top, dst.right, dst.bottom, nativePaint); @@ -694,14 +683,8 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) { throwIfCannotDraw(bitmap); - // Shaders are ignored when drawing bitmaps - int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; - try { - final long nativePaint = paint == null ? 0 : paint.mNativePaint; - nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + final long nativePaint = paint == null ? 0 : paint.mNativePaint; + nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint); } private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer, @@ -710,15 +693,9 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) { throwIfCannotDraw(bitmap); - // Shaders are ignored when drawing bitmaps - int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; - try { - final long nativePaint = paint == null ? 0 : paint.mNativePaint; - nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, - matrix.native_instance, nativePaint); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + final long nativePaint = paint == null ? 0 : paint.mNativePaint; + nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, + matrix.native_instance, nativePaint); } private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer, @@ -727,55 +704,43 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) { throwIfCannotDraw(bitmap); - // Shaders are ignored when drawing bitmaps - int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; - try { - final long nativePaint = paint == null ? 0 : paint.mNativePaint; - - int left, top, right, bottom; - if (src == null) { - left = top = 0; - right = bitmap.getWidth(); - bottom = bitmap.getHeight(); - } else { - left = src.left; - right = src.right; - top = src.top; - bottom = src.bottom; - } + final long nativePaint = paint == null ? 0 : paint.mNativePaint; - nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom, - dst.left, dst.top, dst.right, dst.bottom, nativePaint); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + int left, top, right, bottom; + if (src == null) { + left = top = 0; + right = bitmap.getWidth(); + bottom = bitmap.getHeight(); + } else { + left = src.left; + right = src.right; + top = src.top; + bottom = src.bottom; } + + nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom, + dst.left, dst.top, dst.right, dst.bottom, nativePaint); } @Override public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) { throwIfCannotDraw(bitmap); - // Shaders are ignored when drawing bitmaps - int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; - try { - final long nativePaint = paint == null ? 0 : paint.mNativePaint; - - float left, top, right, bottom; - if (src == null) { - left = top = 0; - right = bitmap.getWidth(); - bottom = bitmap.getHeight(); - } else { - left = src.left; - right = src.right; - top = src.top; - bottom = src.bottom; - } - - nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom, - dst.left, dst.top, dst.right, dst.bottom, nativePaint); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + final long nativePaint = paint == null ? 0 : paint.mNativePaint; + + float left, top, right, bottom; + if (src == null) { + left = top = 0; + right = bitmap.getWidth(); + bottom = bitmap.getHeight(); + } else { + left = src.left; + right = src.right; + top = src.top; + bottom = src.bottom; } + + nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom, + dst.left, dst.top, dst.right, dst.bottom, nativePaint); } private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer, @@ -805,7 +770,6 @@ class GLES20Canvas extends HardwareCanvas { throw new ArrayIndexOutOfBoundsException(); } - // Shaders are ignored when drawing bitmaps final long nativePaint = paint == null ? 0 : paint.mNativePaint; nDrawBitmap(mRenderer, colors, offset, stride, x, y, width, height, hasAlpha, nativePaint); @@ -817,7 +781,6 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawBitmap(int[] colors, int offset, int stride, int x, int y, int width, int height, boolean hasAlpha, Paint paint) { - // Shaders are ignored when drawing bitmaps drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint); } @@ -840,14 +803,9 @@ class GLES20Canvas extends HardwareCanvas { checkRange(colors.length, colorOffset, count); } - int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; - try { - final long nativePaint = paint == null ? 0 : paint.mNativePaint; - nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight, - verts, vertOffset, colors, colorOffset, nativePaint); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + final long nativePaint = paint == null ? 0 : paint.mNativePaint; + nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight, + verts, vertOffset, colors, colorOffset, nativePaint); } private static native void nDrawBitmapMesh(long renderer, long bitmap, byte[] buffer, @@ -856,12 +814,7 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawCircle(float cx, float cy, float radius, Paint paint) { - int modifiers = setupModifiers(paint, MODIFIER_SHADER); - try { - nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint); } private static native void nDrawCircle(long renderer, float cx, float cy, @@ -906,12 +859,7 @@ class GLES20Canvas extends HardwareCanvas { if ((offset | count) < 0 || offset + count > pts.length) { throw new IllegalArgumentException("The lines array must contain 4 elements per line."); } - int modifiers = setupModifiers(paint, MODIFIER_SHADER); - try { - nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint); } private static native void nDrawLines(long renderer, float[] points, @@ -924,12 +872,7 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawOval(RectF oval, Paint paint) { - int modifiers = setupModifiers(paint, MODIFIER_SHADER); - try { - nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint); } private static native void nDrawOval(long renderer, float left, float top, @@ -944,17 +887,12 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawPath(Path path, Paint paint) { - int modifiers = setupModifiers(paint, MODIFIER_SHADER); - try { - if (path.isSimplePath) { - if (path.rects != null) { - nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint); - } - } else { - nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint); + if (path.isSimplePath) { + if (path.rects != null) { + nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint); } - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + } else { + nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint); } } @@ -962,12 +900,7 @@ class GLES20Canvas extends HardwareCanvas { private static native void nDrawRects(long renderer, long region, long paint); void drawRects(float[] rects, int count, Paint paint) { - int modifiers = setupModifiers(paint, MODIFIER_SHADER); - try { - nDrawRects(mRenderer, rects, count, paint.mNativePaint); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + nDrawRects(mRenderer, rects, count, paint.mNativePaint); } private static native void nDrawRects(long renderer, float[] rects, int count, long paint); @@ -1029,12 +962,7 @@ class GLES20Canvas extends HardwareCanvas { public void drawPoints(float[] pts, int offset, int count, Paint paint) { if (count < 2) return; - int modifiers = setupModifiers(paint, MODIFIER_SHADER); - try { - nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint); } private static native void nDrawPoints(long renderer, float[] points, @@ -1047,12 +975,7 @@ class GLES20Canvas extends HardwareCanvas { throw new IndexOutOfBoundsException(); } - int modifiers = setupModifiers(paint); - try { - nDrawPosText(mRenderer, text, index, count, pos, paint.mNativePaint); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + nDrawPosText(mRenderer, text, index, count, pos, paint.mNativePaint); } private static native void nDrawPosText(long renderer, char[] text, int index, int count, @@ -1065,12 +988,7 @@ class GLES20Canvas extends HardwareCanvas { throw new ArrayIndexOutOfBoundsException(); } - int modifiers = setupModifiers(paint); - try { - nDrawPosText(mRenderer, text, 0, text.length(), pos, paint.mNativePaint); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + nDrawPosText(mRenderer, text, 0, text.length(), pos, paint.mNativePaint); } private static native void nDrawPosText(long renderer, String text, int start, int end, @@ -1079,12 +997,7 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawRect(float left, float top, float right, float bottom, Paint paint) { if (left == right || top == bottom) return; - int modifiers = setupModifiers(paint, MODIFIER_SHADER); - try { - nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint); } private static native void nDrawRect(long renderer, float left, float top, @@ -1108,12 +1021,7 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint) { - int modifiers = setupModifiers(paint, MODIFIER_SHADER); - try { - nDrawRoundRect(mRenderer, left, top, right, bottom, rx, ry, paint.mNativePaint); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + nDrawRoundRect(mRenderer, left, top, right, bottom, rx, ry, paint.mNativePaint); } private static native void nDrawRoundRect(long renderer, float left, float top, @@ -1125,13 +1033,8 @@ class GLES20Canvas extends HardwareCanvas { throw new IndexOutOfBoundsException(); } - int modifiers = setupModifiers(paint); - try { - nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint, - paint.mNativeTypeface); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + nDrawText(mRenderer, text, index, count, x, y, + paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface); } private static native void nDrawText(long renderer, char[] text, int index, int count, @@ -1139,24 +1042,18 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) { - int modifiers = setupModifiers(paint); - try { - if (text instanceof String || text instanceof SpannedString || - text instanceof SpannableString) { - nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags, - paint.mNativePaint, paint.mNativeTypeface); - } else if (text instanceof GraphicsOperations) { - ((GraphicsOperations) text).drawText(this, start, end, x, y, - paint); - } else { - char[] buf = TemporaryBuffer.obtain(end - start); - TextUtils.getChars(text, start, end, buf, 0); - nDrawText(mRenderer, buf, 0, end - start, x, y, - paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface); - TemporaryBuffer.recycle(buf); - } - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + if (text instanceof String || text instanceof SpannedString || + text instanceof SpannableString) { + nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags, + paint.mNativePaint, paint.mNativeTypeface); + } else if (text instanceof GraphicsOperations) { + ((GraphicsOperations) text).drawText(this, start, end, x, y, paint); + } else { + char[] buf = TemporaryBuffer.obtain(end - start); + TextUtils.getChars(text, start, end, buf, 0); + nDrawText(mRenderer, buf, 0, end - start, x, y, + paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface); + TemporaryBuffer.recycle(buf); } } @@ -1166,13 +1063,8 @@ class GLES20Canvas extends HardwareCanvas { throw new IndexOutOfBoundsException(); } - int modifiers = setupModifiers(paint); - try { - nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint, - paint.mNativeTypeface); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + nDrawText(mRenderer, text, start, end, x, y, + paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface); } private static native void nDrawText(long renderer, String text, int start, int end, @@ -1180,13 +1072,8 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawText(String text, float x, float y, Paint paint) { - int modifiers = setupModifiers(paint); - try { - nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags, - paint.mNativePaint, paint.mNativeTypeface); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + nDrawText(mRenderer, text, 0, text.length(), x, y, + paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface); } @Override @@ -1196,13 +1083,8 @@ class GLES20Canvas extends HardwareCanvas { throw new ArrayIndexOutOfBoundsException(); } - int modifiers = setupModifiers(paint); - try { - nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset, - paint.mBidiFlags, paint.mNativePaint); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset, + paint.mBidiFlags, paint.mNativePaint); } private static native void nDrawTextOnPath(long renderer, char[] text, int index, int count, @@ -1212,13 +1094,8 @@ class GLES20Canvas extends HardwareCanvas { public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) { if (text.length() == 0) return; - int modifiers = setupModifiers(paint); - try { - nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset, - paint.mBidiFlags, paint.mNativePaint); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset, + paint.mBidiFlags, paint.mNativePaint); } private static native void nDrawTextOnPath(long renderer, String text, int start, int end, @@ -1234,13 +1111,8 @@ class GLES20Canvas extends HardwareCanvas { throw new IllegalArgumentException("Unknown direction: " + dir); } - int modifiers = setupModifiers(paint); - try { - nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir, - paint.mNativePaint, paint.mNativeTypeface); - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); - } + nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir, + paint.mNativePaint, paint.mNativeTypeface); } private static native void nDrawTextRun(long renderer, char[] text, int index, int count, @@ -1253,27 +1125,22 @@ class GLES20Canvas extends HardwareCanvas { throw new IndexOutOfBoundsException(); } - int modifiers = setupModifiers(paint); - try { - int flags = dir == 0 ? 0 : 1; - if (text instanceof String || text instanceof SpannedString || - text instanceof SpannableString) { - nDrawTextRun(mRenderer, text.toString(), start, end, contextStart, - contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface); - } else if (text instanceof GraphicsOperations) { - ((GraphicsOperations) text).drawTextRun(this, start, end, - contextStart, contextEnd, x, y, flags, paint); - } else { - int contextLen = contextEnd - contextStart; - int len = end - start; - char[] buf = TemporaryBuffer.obtain(contextLen); - TextUtils.getChars(text, contextStart, contextEnd, buf, 0); - nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen, - x, y, flags, paint.mNativePaint, paint.mNativeTypeface); - TemporaryBuffer.recycle(buf); - } - } finally { - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + int flags = dir == 0 ? 0 : 1; + if (text instanceof String || text instanceof SpannedString || + text instanceof SpannableString) { + nDrawTextRun(mRenderer, text.toString(), start, end, contextStart, + contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface); + } else if (text instanceof GraphicsOperations) { + ((GraphicsOperations) text).drawTextRun(this, start, end, + contextStart, contextEnd, x, y, flags, paint); + } else { + int contextLen = contextEnd - contextStart; + int len = end - start; + char[] buf = TemporaryBuffer.obtain(contextLen); + TextUtils.getChars(text, contextStart, contextEnd, buf, 0); + nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen, + x, y, flags, paint.mNativePaint, paint.mNativeTypeface); + TemporaryBuffer.recycle(buf); } } @@ -1286,40 +1153,4 @@ class GLES20Canvas extends HardwareCanvas { int indexOffset, int indexCount, Paint paint) { // TODO: Implement } - - private int setupModifiers(Bitmap b, Paint paint) { - if (b.getConfig() != Bitmap.Config.ALPHA_8) { - return MODIFIER_NONE; - } else { - return setupModifiers(paint); - } - } - - private int setupModifiers(Paint paint) { - int modifiers = MODIFIER_NONE; - - final Shader shader = paint.getShader(); - if (shader != null) { - nSetupShader(mRenderer, shader.native_shader); - modifiers |= MODIFIER_SHADER; - } - - return modifiers; - } - - private int setupModifiers(Paint paint, int flags) { - int modifiers = MODIFIER_NONE; - - final Shader shader = paint.getShader(); - if (shader != null && (flags & MODIFIER_SHADER) != 0) { - nSetupShader(mRenderer, shader.native_shader); - modifiers |= MODIFIER_SHADER; - } - - return modifiers; - } - - private static native void nSetupShader(long renderer, long shader); - - private static native void nResetModifiers(long renderer, int modifiers); } diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index a902ce7..3c4d83f 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -579,6 +579,12 @@ public abstract class HardwareRenderer { abstract void fence(); /** + * Called by {@link ViewRootImpl} when a new performTraverals is scheduled. + */ + public void notifyFramePending() { + } + + /** * Describes a series of frames that should be drawn on screen as a graph. * Each frame is composed of 1 or more elements. */ diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 704d516..8417887 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -291,6 +291,11 @@ public class ThreadedRenderer extends HardwareRenderer { } @Override + public void notifyFramePending() { + nNotifyFramePending(mNativeProxy); + } + + @Override protected void finalize() throws Throwable { try { nDeleteProxy(mNativeProxy); @@ -364,4 +369,5 @@ public class ThreadedRenderer extends HardwareRenderer { private static native void nDestroyLayer(long nativeProxy, long layer); private static native void nFence(long nativeProxy); + private static native void nNotifyFramePending(long nativeProxy); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 799a406..fc7bf0e 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -999,6 +999,17 @@ public final class ViewRootImpl implements ViewParent, } } + /** + * Notifies the HardwareRenderer that a new frame will be coming soon. + * Currently only {@link ThreadedRenderer} cares about this, and uses + * this knowledge to adjust the scheduling of off-thread animations + */ + void notifyRendererOfFramePending() { + if (mAttachInfo.mHardwareRenderer != null) { + mAttachInfo.mHardwareRenderer.notifyFramePending(); + } + } + void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; @@ -1006,6 +1017,7 @@ public final class ViewRootImpl implements ViewParent, mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); scheduleConsumeBatchedInput(); + notifyRendererOfFramePending(); } } diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 4fde1e4..1bb20c9 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -1144,6 +1144,12 @@ public interface WindowManagerPolicy { public void setLastInputMethodWindowLw(WindowState ime, WindowState target); /** + * Show the recents task list app. + * @hide + */ + public void showRecentApps(); + + /** * @return The current height of the input method window. */ public int getInputMethodWindowVisibleHeightLw(); diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index 1152e17..43f623b 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -256,6 +256,16 @@ public abstract class AbsSeekBar extends ProgressBar { } @Override + public void invalidateDrawable(Drawable dr) { + super.invalidateDrawable(dr); + + if (dr == mThumb) { + // Handle changes to thumb width and height. + requestLayout(); + } + } + + @Override void onProgressRefresh(float scale, boolean fromUser) { super.onProgressRefresh(scale, fromUser); diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java index 1533510..3ae9508 100644 --- a/core/java/android/widget/CheckedTextView.java +++ b/core/java/android/widget/CheckedTextView.java @@ -24,6 +24,7 @@ import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.Gravity; +import android.view.RemotableViewMethod; import android.view.ViewDebug; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; @@ -156,10 +157,36 @@ public class CheckedTextView extends TextView implements Checkable { mCheckMarkWidth = 0; } mCheckMarkDrawable = d; - // Do padding resolution. This will call internalSetPadding() and do a requestLayout() if needed. + + // Do padding resolution. This will call internalSetPadding() and do a + // requestLayout() if needed. resolvePadding(); } + @RemotableViewMethod + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + + if (mCheckMarkDrawable != null) { + mCheckMarkDrawable.setVisible(visibility == VISIBLE, false); + } + } + + @Override + public void jumpDrawablesToCurrentState() { + super.jumpDrawablesToCurrentState(); + + if (mCheckMarkDrawable != null) { + mCheckMarkDrawable.jumpToCurrentState(); + } + } + + @Override + protected boolean verifyDrawable(Drawable who) { + return who == mCheckMarkDrawable || super.verifyDrawable(who); + } + /** * Gets the checkmark drawable * @@ -249,6 +276,11 @@ public class CheckedTextView extends TextView implements Checkable { } checkMarkDrawable.setBounds(mScrollX + left, top, mScrollX + right, bottom); checkMarkDrawable.draw(canvas); + + final Drawable background = getBackground(); + if (background != null) { + background.setHotspotBounds(mScrollX + left, top, mScrollX + right, bottom); + } } } diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index ad1a023..c5c6e64 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -951,9 +951,8 @@ public class Switch extends CompoundButton { final int[] myDrawableState = getDrawableState(); - if (mThumbDrawable != null && mThumbDrawable.setState(myDrawableState)) { - // Handle changes to thumb width and height. - requestLayout(); + if (mThumbDrawable != null) { + mThumbDrawable.setState(myDrawableState); } if (mTrackDrawable != null) { @@ -964,6 +963,16 @@ public class Switch extends CompoundButton { } @Override + public void invalidateDrawable(Drawable drawable) { + super.invalidateDrawable(drawable); + + if (drawable == mThumbDrawable) { + // Handle changes to thumb width and height. + requestLayout(); + } + } + + @Override protected boolean verifyDrawable(Drawable who) { return super.verifyDrawable(who) || who == mThumbDrawable || who == mTrackDrawable; } diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java index 664f9db..5547a10 100644 --- a/core/java/com/android/internal/app/AlertController.java +++ b/core/java/com/android/internal/app/AlertController.java @@ -1026,7 +1026,7 @@ public class AlertController { ? dialog.mSingleChoiceItemLayout : dialog.mListItemLayout; if (mCursor == null) { adapter = (mAdapter != null) ? mAdapter - : new ArrayAdapter<CharSequence>(mContext, layout, R.id.text1, mItems); + : new CheckedItemAdapter(mContext, layout, R.id.text1, mItems); } else { adapter = new SimpleCursorAdapter(mContext, layout, mCursor, new String[]{mLabelColumn}, new int[]{R.id.text1}); @@ -1081,4 +1081,20 @@ public class AlertController { } } + private static class CheckedItemAdapter extends ArrayAdapter<CharSequence> { + public CheckedItemAdapter(Context context, int resource, int textViewResourceId, + CharSequence[] objects) { + super(context, resource, textViewResourceId, objects); + } + + @Override + public boolean hasStableIds() { + return true; + } + + @Override + public long getItemId(int position) { + return position; + } + } } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 8428f66..ed9f9bc 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -328,11 +328,13 @@ public final class BatteryStatsImpl extends BatteryStats { int mLastDischargeStepLevel; long mLastDischargeStepTime; + int mMinDischargeStepLevel; int mNumDischargeStepDurations; final long[] mDischargeStepDurations = new long[MAX_LEVEL_STEPS]; int mLastChargeStepLevel; long mLastChargeStepTime; + int mMaxChargeStepLevel; int mNumChargeStepDurations; final long[] mChargeStepDurations = new long[MAX_LEVEL_STEPS]; @@ -887,6 +889,7 @@ public final class BatteryStatsImpl extends BatteryStats { mLastTime = 0; mUnpluggedTime = in.readLong(); timeBase.add(this); + if (DEBUG) Log.i(TAG, "**** READ TIMER #" + mType + ": mTotalTime=" + mTotalTime); } Timer(int type, TimeBase timeBase) { @@ -917,6 +920,8 @@ public final class BatteryStatsImpl extends BatteryStats { } public void writeToParcel(Parcel out, long elapsedRealtimeUs) { + if (DEBUG) Log.i(TAG, "**** WRITING TIMER #" + mType + ": mTotalTime=" + + computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs))); out.writeInt(mCount); out.writeInt(mLoadedCount); out.writeInt(mUnpluggedCount); @@ -2337,7 +2342,13 @@ public final class BatteryStatsImpl extends BatteryStats { // Only care about partial wake locks, since full wake locks // will be canceled when the user puts the screen to sleep. aggregateLastWakeupUptimeLocked(uptime); - historyName = historyName == null || mRecordAllWakeLocks ? name : historyName; + if (mRecordAllWakeLocks) { + if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, name, uid, 0)) { + addHistoryEventLocked(elapsedRealtime, uptime, + HistoryItem.EVENT_WAKE_LOCK_START, name, uid); + } + } + historyName = historyName == null ? name : historyName; if (mWakeLockNesting == 0) { mHistoryCur.states |= HistoryItem.STATE_WAKE_LOCK_FLAG; if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: " @@ -2347,7 +2358,7 @@ public final class BatteryStatsImpl extends BatteryStats { mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid; mWakeLockImportant = !unimportantForLogging; addHistoryRecordLocked(elapsedRealtime, uptime); - } else if (!mRecordAllWakeLocks && !mWakeLockImportant && !unimportantForLogging) { + } else if (!mWakeLockImportant && !unimportantForLogging) { if (mHistoryLastWritten.wakelockTag != null) { // We'll try to update the last tag. mHistoryLastWritten.wakelockTag = null; @@ -2357,14 +2368,6 @@ public final class BatteryStatsImpl extends BatteryStats { addHistoryRecordLocked(elapsedRealtime, uptime); } mWakeLockImportant = true; - } else if (mRecordAllWakeLocks) { - if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName, - uid, 0)) { - mWakeLockNesting++; - return; - } - addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_WAKE_LOCK_START, - historyName, uid); } mWakeLockNesting++; } @@ -2382,28 +2385,19 @@ public final class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); if (type == WAKE_TYPE_PARTIAL) { mWakeLockNesting--; - historyName = historyName == null || mRecordAllWakeLocks ? name : historyName; + if (mRecordAllWakeLocks) { + if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, name, uid, 0)) { + addHistoryEventLocked(elapsedRealtime, uptime, + HistoryItem.EVENT_WAKE_LOCK_FINISH, name, uid); + } + } if (mWakeLockNesting == 0) { mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG; if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: " + Integer.toHexString(mHistoryCur.states)); - if (mRecordAllWakeLocks - || (historyName != null && !historyName.equals(mInitialAcquireWakeName)) - || uid != mInitialAcquireWakeUid) { - mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; - mHistoryCur.wakelockTag.string = historyName; - mHistoryCur.wakelockTag.uid = uid; - } mInitialAcquireWakeName = null; mInitialAcquireWakeUid = -1; addHistoryRecordLocked(elapsedRealtime, uptime); - } else if (mRecordAllWakeLocks) { - if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, - uid, 0)) { - return; - } - addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_WAKE_LOCK_FINISH, - historyName, uid); } } if (uid >= 0) { @@ -5550,6 +5544,7 @@ public final class BatteryStatsImpl extends BatteryStats { for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) { mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mOnBatteryTimeBase); } + mInteractiveTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase); mLowPowerModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase); mPhoneOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase); for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) { @@ -5581,7 +5576,6 @@ public final class BatteryStatsImpl extends BatteryStats { } mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase); mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase); - mInteractiveTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase); mOnBattery = mOnBatteryInternal = false; long uptime = SystemClock.uptimeMillis() * 1000; long realtime = SystemClock.elapsedRealtime() * 1000; @@ -5958,6 +5952,7 @@ public final class BatteryStatsImpl extends BatteryStats { mNumDischargeStepDurations = 0; } mLastDischargeStepLevel = level; + mMinDischargeStepLevel = level; mLastDischargeStepTime = -1; pullPendingStateUpdatesLocked(); mHistoryCur.batteryLevel = (byte)level; @@ -5996,6 +5991,7 @@ public final class BatteryStatsImpl extends BatteryStats { updateTimeBasesLocked(false, !screenOn, uptime, realtime); mNumChargeStepDurations = 0; mLastChargeStepLevel = level; + mMaxChargeStepLevel = level; mLastChargeStepTime = -1; } if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) { @@ -6117,19 +6113,21 @@ public final class BatteryStatsImpl extends BatteryStats { addHistoryRecordLocked(elapsedRealtime, uptime); } if (onBattery) { - if (mLastDischargeStepLevel != level) { + if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) { mNumDischargeStepDurations = addLevelSteps(mDischargeStepDurations, mNumDischargeStepDurations, mLastDischargeStepTime, mLastDischargeStepLevel - level, elapsedRealtime); mLastDischargeStepLevel = level; + mMinDischargeStepLevel = level; mLastDischargeStepTime = elapsedRealtime; } } else { - if (mLastChargeStepLevel != level) { + if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) { mNumChargeStepDurations = addLevelSteps(mChargeStepDurations, mNumChargeStepDurations, mLastChargeStepTime, level - mLastChargeStepLevel, elapsedRealtime); mLastChargeStepLevel = level; + mMaxChargeStepLevel = level; mLastChargeStepTime = elapsedRealtime; } } @@ -7495,6 +7493,8 @@ public final class BatteryStatsImpl extends BatteryStats { mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mOnBatteryTimeBase, in); } + mInteractive = false; + mInteractiveTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase, in); mPhoneOn = false; mLowPowerModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in); mPhoneOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase, in); @@ -7536,8 +7536,6 @@ public final class BatteryStatsImpl extends BatteryStats { mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase); mVideoOn = false; mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase); - mInteractive = false; - mInteractiveTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase, in); mDischargeUnplugLevel = in.readInt(); mDischargePlugLevel = in.readInt(); mDischargeCurrentLevel = in.readInt(); diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 1366499..a01e9b7 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -24,9 +24,9 @@ oneway interface IStatusBar { void setIcon(int index, in StatusBarIcon icon); void removeIcon(int index); - void addNotification(IBinder key, in StatusBarNotification notification); - void updateNotification(IBinder key, in StatusBarNotification notification); - void removeNotification(IBinder key); + void addNotification(in StatusBarNotification notification); + void updateNotification(in StatusBarNotification notification); + void removeNotification(String key); void disable(int state); void animateExpandNotificationsPanel(); void animateExpandSettingsPanel(); diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 2d6cf2e..a3b417f 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -39,8 +39,8 @@ interface IStatusBarService // ---- Methods below are for use by the status bar policy services ---- // You need the STATUS_BAR_SERVICE permission void registerStatusBar(IStatusBar callbacks, out StatusBarIconList iconList, - out List<IBinder> notificationKeys, out List<StatusBarNotification> notifications, - out int[] switches, out List<IBinder> binders); + out List<StatusBarNotification> notifications, out int[] switches, + out List<IBinder> binders); void onPanelRevealed(); void onPanelHidden(); void onNotificationClick(String key); diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java index 5b59599..dca9921 100644 --- a/core/java/com/android/internal/util/XmlUtils.java +++ b/core/java/com/android/internal/util/XmlUtils.java @@ -220,28 +220,74 @@ public class XmlUtils { * @see #readMapXml */ public static final void writeMapXml(Map val, String name, XmlSerializer out) - throws XmlPullParserException, java.io.IOException - { + throws XmlPullParserException, java.io.IOException { + writeMapXml(val, name, out, null); + } + + /** + * Flatten a Map into an XmlSerializer. The map can later be read back + * with readThisMapXml(). + * + * @param val The map to be flattened. + * @param name Name attribute to include with this list's tag, or null for + * none. + * @param out XmlSerializer to write the map into. + * @param callback Method to call when an Object type is not recognized. + * + * @see #writeMapXml(Map, OutputStream) + * @see #writeListXml + * @see #writeValueXml + * @see #readMapXml + * + * @hide + */ + public static final void writeMapXml(Map val, String name, XmlSerializer out, + WriteMapCallback callback) throws XmlPullParserException, java.io.IOException { + if (val == null) { out.startTag(null, "null"); out.endTag(null, "null"); return; } - Set s = val.entrySet(); - Iterator i = s.iterator(); - out.startTag(null, "map"); if (name != null) { out.attribute(null, "name", name); } + writeMapXml(val, out, callback); + + out.endTag(null, "map"); + } + + /** + * Flatten a Map into an XmlSerializer. The map can later be read back + * with readThisMapXml(). This method presumes that the start tag and + * name attribute have already been written and does not write an end tag. + * + * @param val The map to be flattened. + * @param out XmlSerializer to write the map into. + * + * @see #writeMapXml(Map, OutputStream) + * @see #writeListXml + * @see #writeValueXml + * @see #readMapXml + * + * @hide + */ + public static final void writeMapXml(Map val, XmlSerializer out, + WriteMapCallback callback) throws XmlPullParserException, java.io.IOException { + if (val == null) { + return; + } + + Set s = val.entrySet(); + Iterator i = s.iterator(); + while (i.hasNext()) { Map.Entry e = (Map.Entry)i.next(); - writeValueXml(e.getValue(), (String)e.getKey(), out); + writeValueXml(e.getValue(), (String)e.getKey(), out, callback); } - - out.endTag(null, "map"); } /** @@ -387,6 +433,123 @@ public class XmlUtils { } /** + * Flatten a long[] into an XmlSerializer. The list can later be read back + * with readThisLongArrayXml(). + * + * @param val The long array to be flattened. + * @param name Name attribute to include with this array's tag, or null for + * none. + * @param out XmlSerializer to write the array into. + * + * @see #writeMapXml + * @see #writeValueXml + * @see #readThisIntArrayXml + */ + public static final void writeLongArrayXml(long[] val, String name, XmlSerializer out) + throws XmlPullParserException, java.io.IOException { + + if (val == null) { + out.startTag(null, "null"); + out.endTag(null, "null"); + return; + } + + out.startTag(null, "long-array"); + if (name != null) { + out.attribute(null, "name", name); + } + + final int N = val.length; + out.attribute(null, "num", Integer.toString(N)); + + for (int i=0; i<N; i++) { + out.startTag(null, "item"); + out.attribute(null, "value", Long.toString(val[i])); + out.endTag(null, "item"); + } + + out.endTag(null, "long-array"); + } + + /** + * Flatten a double[] into an XmlSerializer. The list can later be read back + * with readThisDoubleArrayXml(). + * + * @param val The double array to be flattened. + * @param name Name attribute to include with this array's tag, or null for + * none. + * @param out XmlSerializer to write the array into. + * + * @see #writeMapXml + * @see #writeValueXml + * @see #readThisIntArrayXml + */ + public static final void writeDoubleArrayXml(double[] val, String name, XmlSerializer out) + throws XmlPullParserException, java.io.IOException { + + if (val == null) { + out.startTag(null, "null"); + out.endTag(null, "null"); + return; + } + + out.startTag(null, "double-array"); + if (name != null) { + out.attribute(null, "name", name); + } + + final int N = val.length; + out.attribute(null, "num", Integer.toString(N)); + + for (int i=0; i<N; i++) { + out.startTag(null, "item"); + out.attribute(null, "value", Double.toString(val[i])); + out.endTag(null, "item"); + } + + out.endTag(null, "double-array"); + } + + /** + * Flatten a String[] into an XmlSerializer. The list can later be read back + * with readThisStringArrayXml(). + * + * @param val The long array to be flattened. + * @param name Name attribute to include with this array's tag, or null for + * none. + * @param out XmlSerializer to write the array into. + * + * @see #writeMapXml + * @see #writeValueXml + * @see #readThisIntArrayXml + */ + public static final void writeStringArrayXml(String[] val, String name, XmlSerializer out) + throws XmlPullParserException, java.io.IOException { + + if (val == null) { + out.startTag(null, "null"); + out.endTag(null, "null"); + return; + } + + out.startTag(null, "string-array"); + if (name != null) { + out.attribute(null, "name", name); + } + + final int N = val.length; + out.attribute(null, "num", Integer.toString(N)); + + for (int i=0; i<N; i++) { + out.startTag(null, "item"); + out.attribute(null, "value", val[i]); + out.endTag(null, "item"); + } + + out.endTag(null, "string-array"); + } + + /** * Flatten an object's value into an XmlSerializer. The value can later * be read back with readThisValueXml(). * @@ -403,8 +566,29 @@ public class XmlUtils { * @see #readValueXml */ public static final void writeValueXml(Object v, String name, XmlSerializer out) - throws XmlPullParserException, java.io.IOException - { + throws XmlPullParserException, java.io.IOException { + writeValueXml(v, name, out, null); + } + + /** + * Flatten an object's value into an XmlSerializer. The value can later + * be read back with readThisValueXml(). + * + * Currently supported value types are: null, String, Integer, Long, + * Float, Double Boolean, Map, List. + * + * @param v The object to be flattened. + * @param name Name attribute to include with this value's tag, or null + * for none. + * @param out XmlSerializer to write the object into. + * @param callback Handler for Object types not recognized. + * + * @see #writeMapXml + * @see #writeListXml + * @see #readValueXml + */ + private static final void writeValueXml(Object v, String name, XmlSerializer out, + WriteMapCallback callback) throws XmlPullParserException, java.io.IOException { String typeStr; if (v == null) { out.startTag(null, "null"); @@ -437,14 +621,23 @@ public class XmlUtils { } else if (v instanceof int[]) { writeIntArrayXml((int[])v, name, out); return; + } else if (v instanceof long[]) { + writeLongArrayXml((long[])v, name, out); + return; + } else if (v instanceof double[]) { + writeDoubleArrayXml((double[])v, name, out); + return; + } else if (v instanceof String[]) { + writeStringArrayXml((String[])v, name, out); + return; } else if (v instanceof Map) { writeMapXml((Map)v, name, out); return; } else if (v instanceof List) { - writeListXml((List)v, name, out); + writeListXml((List) v, name, out); return; } else if (v instanceof Set) { - writeSetXml((Set)v, name, out); + writeSetXml((Set) v, name, out); return; } else if (v instanceof CharSequence) { // XXX This is to allow us to at least write something if @@ -457,6 +650,9 @@ public class XmlUtils { out.text(v.toString()); out.endTag(null, "string"); return; + } else if (callback != null) { + callback.writeUnknownObject(v, name, out); + return; } else { throw new RuntimeException("writeValueXml: unable to write value " + v); } @@ -550,14 +746,35 @@ public class XmlUtils { * @see #readMapXml */ public static final HashMap<String, ?> readThisMapXml(XmlPullParser parser, String endTag, - String[] name) throws XmlPullParserException, java.io.IOException + String[] name) throws XmlPullParserException, java.io.IOException { + return readThisMapXml(parser, endTag, name, null); + } + + /** + * Read a HashMap object from an XmlPullParser. The XML data could + * previously have been generated by writeMapXml(). The XmlPullParser + * must be positioned <em>after</em> the tag that begins the map. + * + * @param parser The XmlPullParser from which to read the map data. + * @param endTag Name of the tag that will end the map, usually "map". + * @param name An array of one string, used to return the name attribute + * of the map's tag. + * + * @return HashMap The newly generated map. + * + * @see #readMapXml + * @hide + */ + public static final HashMap<String, ?> readThisMapXml(XmlPullParser parser, String endTag, + String[] name, ReadMapCallback callback) + throws XmlPullParserException, java.io.IOException { HashMap<String, Object> map = new HashMap<String, Object>(); int eventType = parser.getEventType(); do { if (eventType == parser.START_TAG) { - Object val = readThisValueXml(parser, name); + Object val = readThisValueXml(parser, name, callback); map.put(name[0], val); } else if (eventType == parser.END_TAG) { if (parser.getName().equals(endTag)) { @@ -587,15 +804,34 @@ public class XmlUtils { * * @see #readListXml */ - public static final ArrayList readThisListXml(XmlPullParser parser, String endTag, String[] name) - throws XmlPullParserException, java.io.IOException - { + public static final ArrayList readThisListXml(XmlPullParser parser, String endTag, + String[] name) throws XmlPullParserException, java.io.IOException { + return readThisListXml(parser, endTag, name, null); + } + + /** + * Read an ArrayList object from an XmlPullParser. The XML data could + * previously have been generated by writeListXml(). The XmlPullParser + * must be positioned <em>after</em> the tag that begins the list. + * + * @param parser The XmlPullParser from which to read the list data. + * @param endTag Name of the tag that will end the list, usually "list". + * @param name An array of one string, used to return the name attribute + * of the list's tag. + * + * @return HashMap The newly generated list. + * + * @see #readListXml + */ + private static final ArrayList readThisListXml(XmlPullParser parser, String endTag, + String[] name, ReadMapCallback callback) + throws XmlPullParserException, java.io.IOException { ArrayList list = new ArrayList(); int eventType = parser.getEventType(); do { if (eventType == parser.START_TAG) { - Object val = readThisValueXml(parser, name); + Object val = readThisValueXml(parser, name, callback); list.add(val); //System.out.println("Adding to list: " + val); } else if (eventType == parser.END_TAG) { @@ -611,7 +847,29 @@ public class XmlUtils { throw new XmlPullParserException( "Document ended before " + endTag + " end tag"); } - + + /** + * Read a HashSet object from an XmlPullParser. The XML data could previously + * have been generated by writeSetXml(). The XmlPullParser must be positioned + * <em>after</em> the tag that begins the set. + * + * @param parser The XmlPullParser from which to read the set data. + * @param endTag Name of the tag that will end the set, usually "set". + * @param name An array of one string, used to return the name attribute + * of the set's tag. + * + * @return HashSet The newly generated set. + * + * @throws XmlPullParserException + * @throws java.io.IOException + * + * @see #readSetXml + */ + public static final HashSet readThisSetXml(XmlPullParser parser, String endTag, String[] name) + throws XmlPullParserException, java.io.IOException { + return readThisSetXml(parser, endTag, name, null); + } + /** * Read a HashSet object from an XmlPullParser. The XML data could previously * have been generated by writeSetXml(). The XmlPullParser must be positioned @@ -628,15 +886,16 @@ public class XmlUtils { * @throws java.io.IOException * * @see #readSetXml + * @hide */ - public static final HashSet readThisSetXml(XmlPullParser parser, String endTag, String[] name) - throws XmlPullParserException, java.io.IOException { + private static final HashSet readThisSetXml(XmlPullParser parser, String endTag, String[] name, + ReadMapCallback callback) throws XmlPullParserException, java.io.IOException { HashSet set = new HashSet(); int eventType = parser.getEventType(); do { if (eventType == parser.START_TAG) { - Object val = readThisValueXml(parser, name); + Object val = readThisValueXml(parser, name, callback); set.add(val); //System.out.println("Adding to set: " + val); } else if (eventType == parser.END_TAG) { @@ -681,6 +940,7 @@ public class XmlUtils { throw new XmlPullParserException( "Not a number in num attribute in byte-array"); } + parser.next(); int[] array = new int[num]; int i = 0; @@ -722,6 +982,187 @@ public class XmlUtils { } /** + * Read a long[] object from an XmlPullParser. The XML data could + * previously have been generated by writeLongArrayXml(). The XmlPullParser + * must be positioned <em>after</em> the tag that begins the list. + * + * @param parser The XmlPullParser from which to read the list data. + * @param endTag Name of the tag that will end the list, usually "list". + * @param name An array of one string, used to return the name attribute + * of the list's tag. + * + * @return Returns a newly generated long[]. + * + * @see #readListXml + */ + public static final long[] readThisLongArrayXml(XmlPullParser parser, + String endTag, String[] name) + throws XmlPullParserException, java.io.IOException { + + int num; + try { + num = Integer.parseInt(parser.getAttributeValue(null, "num")); + } catch (NullPointerException e) { + throw new XmlPullParserException("Need num attribute in long-array"); + } catch (NumberFormatException e) { + throw new XmlPullParserException("Not a number in num attribute in long-array"); + } + parser.next(); + + long[] array = new long[num]; + int i = 0; + + int eventType = parser.getEventType(); + do { + if (eventType == parser.START_TAG) { + if (parser.getName().equals("item")) { + try { + array[i] = Long.parseLong(parser.getAttributeValue(null, "value")); + } catch (NullPointerException e) { + throw new XmlPullParserException("Need value attribute in item"); + } catch (NumberFormatException e) { + throw new XmlPullParserException("Not a number in value attribute in item"); + } + } else { + throw new XmlPullParserException("Expected item tag at: " + parser.getName()); + } + } else if (eventType == parser.END_TAG) { + if (parser.getName().equals(endTag)) { + return array; + } else if (parser.getName().equals("item")) { + i++; + } else { + throw new XmlPullParserException("Expected " + endTag + " end tag at: " + + parser.getName()); + } + } + eventType = parser.next(); + } while (eventType != parser.END_DOCUMENT); + + throw new XmlPullParserException("Document ended before " + endTag + " end tag"); + } + + /** + * Read a double[] object from an XmlPullParser. The XML data could + * previously have been generated by writeDoubleArrayXml(). The XmlPullParser + * must be positioned <em>after</em> the tag that begins the list. + * + * @param parser The XmlPullParser from which to read the list data. + * @param endTag Name of the tag that will end the list, usually "double-array". + * @param name An array of one string, used to return the name attribute + * of the list's tag. + * + * @return Returns a newly generated double[]. + * + * @see #readListXml + */ + public static final double[] readThisDoubleArrayXml(XmlPullParser parser, String endTag, + String[] name) throws XmlPullParserException, java.io.IOException { + + int num; + try { + num = Integer.parseInt(parser.getAttributeValue(null, "num")); + } catch (NullPointerException e) { + throw new XmlPullParserException("Need num attribute in double-array"); + } catch (NumberFormatException e) { + throw new XmlPullParserException("Not a number in num attribute in double-array"); + } + parser.next(); + + double[] array = new double[num]; + int i = 0; + + int eventType = parser.getEventType(); + do { + if (eventType == parser.START_TAG) { + if (parser.getName().equals("item")) { + try { + array[i] = Double.parseDouble(parser.getAttributeValue(null, "value")); + } catch (NullPointerException e) { + throw new XmlPullParserException("Need value attribute in item"); + } catch (NumberFormatException e) { + throw new XmlPullParserException("Not a number in value attribute in item"); + } + } else { + throw new XmlPullParserException("Expected item tag at: " + parser.getName()); + } + } else if (eventType == parser.END_TAG) { + if (parser.getName().equals(endTag)) { + return array; + } else if (parser.getName().equals("item")) { + i++; + } else { + throw new XmlPullParserException("Expected " + endTag + " end tag at: " + + parser.getName()); + } + } + eventType = parser.next(); + } while (eventType != parser.END_DOCUMENT); + + throw new XmlPullParserException("Document ended before " + endTag + " end tag"); + } + + /** + * Read a String[] object from an XmlPullParser. The XML data could + * previously have been generated by writeStringArrayXml(). The XmlPullParser + * must be positioned <em>after</em> the tag that begins the list. + * + * @param parser The XmlPullParser from which to read the list data. + * @param endTag Name of the tag that will end the list, usually "string-array". + * @param name An array of one string, used to return the name attribute + * of the list's tag. + * + * @return Returns a newly generated String[]. + * + * @see #readListXml + */ + public static final String[] readThisStringArrayXml(XmlPullParser parser, String endTag, + String[] name) throws XmlPullParserException, java.io.IOException { + + int num; + try { + num = Integer.parseInt(parser.getAttributeValue(null, "num")); + } catch (NullPointerException e) { + throw new XmlPullParserException("Need num attribute in string-array"); + } catch (NumberFormatException e) { + throw new XmlPullParserException("Not a number in num attribute in string-array"); + } + parser.next(); + + String[] array = new String[num]; + int i = 0; + + int eventType = parser.getEventType(); + do { + if (eventType == parser.START_TAG) { + if (parser.getName().equals("item")) { + try { + array[i] = parser.getAttributeValue(null, "value"); + } catch (NullPointerException e) { + throw new XmlPullParserException("Need value attribute in item"); + } catch (NumberFormatException e) { + throw new XmlPullParserException("Not a number in value attribute in item"); + } + } else { + throw new XmlPullParserException("Expected item tag at: " + parser.getName()); + } + } else if (eventType == parser.END_TAG) { + if (parser.getName().equals(endTag)) { + return array; + } else if (parser.getName().equals("item")) { + i++; + } else { + throw new XmlPullParserException("Expected " + endTag + " end tag at: " + + parser.getName()); + } + } + eventType = parser.next(); + } while (eventType != parser.END_DOCUMENT); + + throw new XmlPullParserException("Document ended before " + endTag + " end tag"); + } + + /** * Read a flattened object from an XmlPullParser. The XML data could * previously have been written with writeMapXml(), writeListXml(), or * writeValueXml(). The XmlPullParser must be positioned <em>at</em> the @@ -743,7 +1184,7 @@ public class XmlUtils { int eventType = parser.getEventType(); do { if (eventType == parser.START_TAG) { - return readThisValueXml(parser, name); + return readThisValueXml(parser, name, null); } else if (eventType == parser.END_TAG) { throw new XmlPullParserException( "Unexpected end tag at: " + parser.getName()); @@ -758,9 +1199,8 @@ public class XmlUtils { "Unexpected end of document"); } - private static final Object readThisValueXml(XmlPullParser parser, String[] name) - throws XmlPullParserException, java.io.IOException - { + private static final Object readThisValueXml(XmlPullParser parser, String[] name, + ReadMapCallback callback) throws XmlPullParserException, java.io.IOException { final String valueName = parser.getAttributeValue(null, "name"); final String tagName = parser.getName(); @@ -794,11 +1234,25 @@ public class XmlUtils { } else if ((res = readThisPrimitiveValueXml(parser, tagName)) != null) { // all work already done by readThisPrimitiveValueXml } else if (tagName.equals("int-array")) { - parser.next(); res = readThisIntArrayXml(parser, "int-array", name); name[0] = valueName; //System.out.println("Returning value for " + valueName + ": " + res); return res; + } else if (tagName.equals("long-array")) { + res = readThisLongArrayXml(parser, "long-array", name); + name[0] = valueName; + //System.out.println("Returning value for " + valueName + ": " + res); + return res; + } else if (tagName.equals("double-array")) { + res = readThisDoubleArrayXml(parser, "double-array", name); + name[0] = valueName; + //System.out.println("Returning value for " + valueName + ": " + res); + return res; + } else if (tagName.equals("string-array")) { + res = readThisStringArrayXml(parser, "string-array", name); + name[0] = valueName; + //System.out.println("Returning value for " + valueName + ": " + res); + return res; } else if (tagName.equals("map")) { parser.next(); res = readThisMapXml(parser, "map", name); @@ -817,9 +1271,12 @@ public class XmlUtils { name[0] = valueName; //System.out.println("Returning value for " + valueName + ": " + res); return res; + } else if (callback != null) { + res = callback.readThisUnknownObjectXml(parser, tagName); + name[0] = valueName; + return res; } else { - throw new XmlPullParserException( - "Unknown tag: " + tagName); + throw new XmlPullParserException("Unknown tag: " + tagName); } // Skip through to end tag. @@ -967,4 +1424,39 @@ public class XmlUtils { throws IOException { out.attribute(null, name, Boolean.toString(value)); } + + /** @hide */ + public interface WriteMapCallback { + /** + * Called from writeMapXml when an Object type is not recognized. The implementer + * must write out the entire element including start and end tags. + * + * @param v The object to be written out + * @param name The mapping key for v. Must be written into the "name" attribute of the + * start tag. + * @param out The XML output stream. + * @throws XmlPullParserException on unrecognized Object type. + * @throws IOException on XmlSerializer serialization errors. + * @hide + */ + public void writeUnknownObject(Object v, String name, XmlSerializer out) + throws XmlPullParserException, IOException; + } + + /** @hide */ + public interface ReadMapCallback { + /** + * Called from readThisMapXml when a START_TAG is not recognized. The input stream + * is positioned within the start tag so that attributes can be read using in.getAttribute. + * + * @param in the XML input stream + * @param tag the START_TAG that was not recognized. + * @return the Object parsed from the stream which will be put into the map. + * @throws XmlPullParserException if the START_TAG is not recognized. + * @throws IOException on XmlPullParser serialization errors. + * @hide + */ + public Object readThisUnknownObjectXml(XmlPullParser in, String tag) + throws XmlPullParserException, IOException; + } } diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index 9501f92..c70841b 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -16,6 +16,8 @@ package com.android.internal.widget; +import com.android.internal.widget.ILockSettingsObserver; + /** {@hide} */ interface ILockSettings { void setBoolean(in String key, in boolean value, in int userId); @@ -32,4 +34,6 @@ interface ILockSettings { boolean havePattern(int userId); boolean havePassword(int userId); void removeUser(int userId); + void registerObserver(in ILockSettingsObserver observer); + void unregisterObserver(in ILockSettingsObserver observer); } diff --git a/core/java/com/android/internal/widget/ILockSettingsObserver.aidl b/core/java/com/android/internal/widget/ILockSettingsObserver.aidl new file mode 100644 index 0000000..6c354d8 --- /dev/null +++ b/core/java/com/android/internal/widget/ILockSettingsObserver.aidl @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.widget; + +/** {@hide} */ +oneway interface ILockSettingsObserver { + void onLockSettingChanged(in String key, in int userId); +} diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 2882b54..25e3463 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -199,8 +199,8 @@ public class LockPatternUtils { private ILockSettings getLockSettings() { if (mLockSettingsService == null) { - mLockSettingsService = ILockSettings.Stub.asInterface( - (IBinder) ServiceManager.getService("lock_settings")); + mLockSettingsService = LockPatternUtilsCache.getInstance( + ILockSettings.Stub.asInterface(ServiceManager.getService("lock_settings"))); } return mLockSettingsService; } diff --git a/core/java/com/android/internal/widget/LockPatternUtilsCache.java b/core/java/com/android/internal/widget/LockPatternUtilsCache.java new file mode 100644 index 0000000..550aa6d --- /dev/null +++ b/core/java/com/android/internal/widget/LockPatternUtilsCache.java @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.internal.widget; + +import android.os.IBinder; +import android.os.RemoteException; +import android.util.ArrayMap; + +/** + * A decorator for {@link ILockSettings} that caches the key-value responses in memory. + * + * Specifically, the return values of {@link #getString(String, String, int)}, + * {@link #getLong(String, long, int)} and {@link #getBoolean(String, boolean, int)} are cached. + */ +public class LockPatternUtilsCache implements ILockSettings { + + private static LockPatternUtilsCache sInstance; + + private final ILockSettings mService; + + /** Only access when holding {@code mCache} lock. */ + private final ArrayMap<CacheKey, Object> mCache = new ArrayMap<>(); + + /** Only access when holding {@link #mCache} lock. */ + private final CacheKey mCacheKey = new CacheKey(); + + + public static synchronized LockPatternUtilsCache getInstance(ILockSettings service) { + if (sInstance == null) { + sInstance = new LockPatternUtilsCache(service); + } + return sInstance; + } + + // ILockSettings + + private LockPatternUtilsCache(ILockSettings service) { + mService = service; + try { + service.registerObserver(mObserver); + } catch (RemoteException e) { + // Not safe to do caching without the observer. System process has probably died + // anyway, so crashing here is fine. + throw new RuntimeException(e); + } + } + + public void setBoolean(String key, boolean value, int userId) throws RemoteException { + invalidateCache(key, userId); + mService.setBoolean(key, value, userId); + putCache(key, userId, value); + } + + public void setLong(String key, long value, int userId) throws RemoteException { + invalidateCache(key, userId); + mService.setLong(key, value, userId); + putCache(key, userId, value); + } + + public void setString(String key, String value, int userId) throws RemoteException { + invalidateCache(key, userId); + mService.setString(key, value, userId); + putCache(key, userId, value); + } + + public long getLong(String key, long defaultValue, int userId) throws RemoteException { + Object value = peekCache(key, userId); + if (value instanceof Long) { + return (long) value; + } + long result = mService.getLong(key, defaultValue, userId); + putCache(key, userId, result); + return result; + } + + public String getString(String key, String defaultValue, int userId) throws RemoteException { + Object value = peekCache(key, userId); + if (value instanceof String) { + return (String) value; + } + String result = mService.getString(key, defaultValue, userId); + putCache(key, userId, result); + return result; + } + + public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException { + Object value = peekCache(key, userId); + if (value instanceof Boolean) { + return (boolean) value; + } + boolean result = mService.getBoolean(key, defaultValue, userId); + putCache(key, userId, result); + return result; + } + + @Override + public void setLockPattern(String pattern, int userId) throws RemoteException { + mService.setLockPattern(pattern, userId); + } + + @Override + public boolean checkPattern(String pattern, int userId) throws RemoteException { + return mService.checkPattern(pattern, userId); + } + + @Override + public void setLockPassword(String password, int userId) throws RemoteException { + mService.setLockPassword(password, userId); + } + + @Override + public boolean checkPassword(String password, int userId) throws RemoteException { + return mService.checkPassword(password, userId); + } + + @Override + public boolean checkVoldPassword(int userId) throws RemoteException { + return mService.checkVoldPassword(userId); + } + + @Override + public boolean havePattern(int userId) throws RemoteException { + return mService.havePattern(userId); + } + + @Override + public boolean havePassword(int userId) throws RemoteException { + return mService.havePassword(userId); + } + + @Override + public void removeUser(int userId) throws RemoteException { + mService.removeUser(userId); + } + + @Override + public void registerObserver(ILockSettingsObserver observer) throws RemoteException { + mService.registerObserver(observer); + } + + @Override + public void unregisterObserver(ILockSettingsObserver observer) throws RemoteException { + mService.unregisterObserver(observer); + } + + @Override + public IBinder asBinder() { + return mService.asBinder(); + } + + // Caching + + private Object peekCache(String key, int userId) { + synchronized (mCache) { + // Safe to reuse mCacheKey, because it is not stored in the map. + return mCache.get(mCacheKey.set(key, userId)); + } + } + + private void putCache(String key, int userId, Object value) { + synchronized (mCache) { + // Create a new key, because this will be stored in the map. + mCache.put(new CacheKey().set(key, userId), value); + } + } + + private void invalidateCache(String key, int userId) { + synchronized (mCache) { + // Safe to reuse mCacheKey, because it is not stored in the map. + mCache.remove(mCacheKey.set(key, userId)); + } + } + + private final ILockSettingsObserver mObserver = new ILockSettingsObserver.Stub() { + @Override + public void onLockSettingChanged(String key, int userId) throws RemoteException { + invalidateCache(key, userId); + } + }; + + private static final class CacheKey { + String key; + int userId; + + public CacheKey set(String key, int userId) { + this.key = key; + this.userId = userId; + return this; + } + + public CacheKey copy() { + return new CacheKey().set(key, userId); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof CacheKey)) + return false; + CacheKey o = (CacheKey) obj; + return userId == o.userId && key.equals(o.key); + } + + @Override + public int hashCode() { + return key.hashCode() ^ userId; + } + } +} diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 835a648..a159715 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -138,6 +138,7 @@ LOCAL_SRC_FILES:= \ android_hardware_Camera.cpp \ android_hardware_camera2_CameraMetadata.cpp \ android_hardware_camera2_legacy_LegacyCameraDevice.cpp \ + android_hardware_camera2_DngCreator.cpp \ android_hardware_SensorManager.cpp \ android_hardware_SerialPort.cpp \ android_hardware_UsbDevice.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 2d350e0..0c7eefa 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -80,6 +80,7 @@ extern int register_android_opengl_jni_GLES31Ext(JNIEnv* env); extern int register_android_hardware_Camera(JNIEnv *env); extern int register_android_hardware_camera2_CameraMetadata(JNIEnv *env); extern int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv *env); +extern int register_android_hardware_camera2_DngCreator(JNIEnv *env); extern int register_android_hardware_SensorManager(JNIEnv *env); extern int register_android_hardware_SerialPort(JNIEnv *env); extern int register_android_hardware_UsbDevice(JNIEnv *env); @@ -1286,6 +1287,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_hardware_Camera), REG_JNI(register_android_hardware_camera2_CameraMetadata), REG_JNI(register_android_hardware_camera2_legacy_LegacyCameraDevice), + REG_JNI(register_android_hardware_camera2_DngCreator), REG_JNI(register_android_hardware_SensorManager), REG_JNI(register_android_hardware_SerialPort), REG_JNI(register_android_hardware_UsbDevice), diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp index b389d9e..0cfcaef 100644 --- a/core/jni/android/graphics/Shader.cpp +++ b/core/jni/android/graphics/Shader.cpp @@ -50,26 +50,16 @@ static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvAr /////////////////////////////////////////////////////////////////////////////////////////////// -static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle, jlong skiaShaderHandle) +static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle) { SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle); - SkiaShader* skiaShader = reinterpret_cast<SkiaShader*>(skiaShaderHandle); SkSafeUnref(shader); - // skiaShader == NULL when not !USE_OPENGL_RENDERER, so no need to delete it outside the ifdef -#ifdef USE_OPENGL_RENDERER - if (android::uirenderer::Caches::hasInstance()) { - android::uirenderer::Caches::getInstance().resourceCache.destructor(skiaShader); - } else { - delete skiaShader; - } -#endif } static void Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle, - jlong skiaShaderHandle, jlong matrixHandle) + jlong matrixHandle) { SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle); - SkiaShader* skiaShader = reinterpret_cast<SkiaShader*>(skiaShaderHandle); const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); if (shader) { if (NULL == matrix) { @@ -78,9 +68,6 @@ static void Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle, else { shader->setLocalMatrix(*matrix); } -#ifdef USE_OPENGL_RENDERER - skiaShader->setMatrix(const_cast<SkMatrix*>(matrix)); -#endif } } @@ -98,20 +85,6 @@ static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong bitmapHandle return reinterpret_cast<jlong>(s); } -static jlong BitmapShader_postConstructor(JNIEnv* env, jobject o, jlong shaderHandle, - jlong bitmapHandle, jint tileModeX, jint tileModeY) { - SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle); - SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); -#ifdef USE_OPENGL_RENDERER - SkiaShader* skiaShader = new SkiaBitmapShader(bitmap, shader, - static_cast<SkShader::TileMode>(tileModeX), static_cast<SkShader::TileMode>(tileModeY), - NULL, !shader->isOpaque()); - return reinterpret_cast<jlong>(skiaShader); -#else - return NULL; -#endif -} - /////////////////////////////////////////////////////////////////////////////////////////////// static jlong LinearGradient_create1(JNIEnv* env, jobject o, @@ -141,105 +114,6 @@ static jlong LinearGradient_create1(JNIEnv* env, jobject o, return reinterpret_cast<jlong>(shader); } -static jlong LinearGradient_postCreate1(JNIEnv* env, jobject o, jlong shaderHandle, - jfloat x0, jfloat y0, jfloat x1, jfloat y1, jintArray colorArray, - jfloatArray posArray, jint tileMode) { -#ifdef USE_OPENGL_RENDERER - SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle); - size_t count = env->GetArrayLength(colorArray); - const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); - - jfloat* storedBounds = new jfloat[4]; - storedBounds[0] = x0; storedBounds[1] = y0; - storedBounds[2] = x1; storedBounds[3] = y1; - - bool missFirst = false; - bool missLast = false; - size_t stopCount = count; - - jfloat* storedPositions = NULL; - if (posArray) { - AutoJavaFloatArray autoPos(env, posArray, count); - const float* posValues = autoPos.ptr(); - - missFirst = posValues[0] != 0.0f; - missLast = posValues[count - 1] != 1.0f; - - stopCount += missFirst + missLast; - storedPositions = new jfloat[stopCount]; - - if (missFirst) { - storedPositions[0] = 0.0f; - } - - for (size_t i = missFirst; i < count + missFirst; i++) { - storedPositions[i] = posValues[i - missFirst]; - } - - if (missLast) { - storedPositions[stopCount - 1] = 1.0f; - } - } else { - storedPositions = new jfloat[count]; - storedPositions[0] = 0.0f; - const jfloat step = 1.0f / (count - 1); - for (size_t i = 1; i < count - 1; i++) { - storedPositions[i] = step * i; - } - storedPositions[count - 1] = 1.0f; - } - - uint32_t* storedColors = new uint32_t[stopCount]; - - if (missFirst) { - storedColors[0] = static_cast<uint32_t>(colorValues[0]); - } - - for (size_t i = missFirst; i < count + missFirst; i++) { - storedColors[i] = static_cast<uint32_t>(colorValues[i - missFirst]); - } - - if (missLast) { - storedColors[stopCount - 1] = static_cast<uint32_t>(colorValues[count - 1]); - } - - SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors, - storedPositions, stopCount, shader, static_cast<SkShader::TileMode>(tileMode), NULL, - !shader->isOpaque()); - - env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT); - return reinterpret_cast<jlong>(skiaShader); -#else - return NULL; -#endif -} - -static jlong LinearGradient_postCreate2(JNIEnv* env, jobject o, jlong shaderHandle, - jfloat x0, jfloat y0, jfloat x1, jfloat y1, jint color0, jint color1, jint tileMode) { -#ifdef USE_OPENGL_RENDERER - SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle); - float* storedBounds = new float[4]; - storedBounds[0] = x0; storedBounds[1] = y0; - storedBounds[2] = x1; storedBounds[3] = y1; - - float* storedPositions = new float[2]; - storedPositions[0] = 0.0f; - storedPositions[1] = 1.0f; - - uint32_t* storedColors = new uint32_t[2]; - storedColors[0] = static_cast<uint32_t>(color0); - storedColors[1] = static_cast<uint32_t>(color1); - - SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors, - storedPositions, 2, shader, static_cast<SkShader::TileMode>(tileMode), NULL, - !shader->isOpaque()); - - return reinterpret_cast<jlong>(skiaShader); -#else - return NULL; -#endif -} - static jlong LinearGradient_create2(JNIEnv* env, jobject o, jfloat x0, jfloat y0, jfloat x1, jfloat y1, jint color0, jint color1, jint tileMode) @@ -300,67 +174,6 @@ static jlong RadialGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y, jf return reinterpret_cast<jlong>(s); } -static jlong RadialGradient_postCreate1(JNIEnv* env, jobject o, jlong shaderHandle, - jfloat x, jfloat y, jfloat radius, jintArray colorArray, jfloatArray posArray, jint tileMode) { -#ifdef USE_OPENGL_RENDERER - SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle); - size_t count = env->GetArrayLength(colorArray); - const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); - - jfloat* storedPositions = new jfloat[count]; - uint32_t* storedColors = new uint32_t[count]; - for (size_t i = 0; i < count; i++) { - storedColors[i] = static_cast<uint32_t>(colorValues[i]); - } - - if (posArray) { - AutoJavaFloatArray autoPos(env, posArray, count); - const float* posValues = autoPos.ptr(); - for (size_t i = 0; i < count; i++) { - storedPositions[i] = posValues[i]; - } - } else { - storedPositions[0] = 0.0f; - const jfloat step = 1.0f / (count - 1); - for (size_t i = 1; i < count - 1; i++) { - storedPositions[i] = step * i; - } - storedPositions[count - 1] = 1.0f; - } - - SkiaShader* skiaShader = new SkiaCircularGradientShader(x, y, radius, storedColors, - storedPositions, count, shader, (SkShader::TileMode) tileMode, NULL, - !shader->isOpaque()); - - env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT); - return reinterpret_cast<jlong>(skiaShader); -#else - return NULL; -#endif -} - -static jlong RadialGradient_postCreate2(JNIEnv* env, jobject o, jlong shaderHandle, - jfloat x, jfloat y, jfloat radius, jint color0, jint color1, jint tileMode) { -#ifdef USE_OPENGL_RENDERER - SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle); - float* storedPositions = new float[2]; - storedPositions[0] = 0.0f; - storedPositions[1] = 1.0f; - - uint32_t* storedColors = new uint32_t[2]; - storedColors[0] = static_cast<uint32_t>(color0); - storedColors[1] = static_cast<uint32_t>(color1); - - SkiaShader* skiaShader = new SkiaCircularGradientShader(x, y, radius, storedColors, - storedPositions, 2, shader, (SkShader::TileMode) tileMode, NULL, - !shader->isOpaque()); - - return reinterpret_cast<jlong>(skiaShader); -#else - return NULL; -#endif -} - /////////////////////////////////////////////////////////////////////////////// static jlong SweepGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y, @@ -393,65 +206,6 @@ static jlong SweepGradient_create2(JNIEnv* env, jobject, jfloat x, jfloat y, return reinterpret_cast<jlong>(s); } -static jlong SweepGradient_postCreate1(JNIEnv* env, jobject o, jlong shaderHandle, - jfloat x, jfloat y, jintArray colorArray, jfloatArray posArray) { -#ifdef USE_OPENGL_RENDERER - SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle); - size_t count = env->GetArrayLength(colorArray); - const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); - - jfloat* storedPositions = new jfloat[count]; - uint32_t* storedColors = new uint32_t[count]; - for (size_t i = 0; i < count; i++) { - storedColors[i] = static_cast<uint32_t>(colorValues[i]); - } - - if (posArray) { - AutoJavaFloatArray autoPos(env, posArray, count); - const float* posValues = autoPos.ptr(); - for (size_t i = 0; i < count; i++) { - storedPositions[i] = posValues[i]; - } - } else { - storedPositions[0] = 0.0f; - const jfloat step = 1.0f / (count - 1); - for (size_t i = 1; i < count - 1; i++) { - storedPositions[i] = step * i; - } - storedPositions[count - 1] = 1.0f; - } - - SkiaShader* skiaShader = new SkiaSweepGradientShader(x, y, storedColors, storedPositions, count, - shader, NULL, !shader->isOpaque()); - - env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT); - return reinterpret_cast<jlong>(skiaShader); -#else - return NULL; -#endif -} - -static jlong SweepGradient_postCreate2(JNIEnv* env, jobject o, jlong shaderHandle, - jfloat x, jfloat y, jint color0, jint color1) { -#ifdef USE_OPENGL_RENDERER - SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle); - float* storedPositions = new float[2]; - storedPositions[0] = 0.0f; - storedPositions[1] = 1.0f; - - uint32_t* storedColors = new uint32_t[2]; - storedColors[0] = static_cast<uint32_t>(color0); - storedColors[1] = static_cast<uint32_t>(color1); - - SkiaShader* skiaShader = new SkiaSweepGradientShader(x, y, storedColors, storedPositions, 2, - shader, NULL, !shader->isOpaque()); - - return reinterpret_cast<jlong>(skiaShader); -#else - return NULL; -#endif -} - /////////////////////////////////////////////////////////////////////////////////////////////// static jlong ComposeShader_create1(JNIEnv* env, jobject o, @@ -476,40 +230,6 @@ static jlong ComposeShader_create2(JNIEnv* env, jobject o, return reinterpret_cast<jlong>(shader); } -static jlong ComposeShader_postCreate2(JNIEnv* env, jobject o, jlong shaderHandle, - jlong shaderAHandle, jlong shaderBHandle, jint porterDuffModeHandle) { -#ifdef USE_OPENGL_RENDERER - SkShader* shader = reinterpret_cast<SkShader *>(shaderHandle); - SkiaShader* shaderA = reinterpret_cast<SkiaShader *>(shaderAHandle); - SkiaShader* shaderB = reinterpret_cast<SkiaShader *>(shaderBHandle); - SkPorterDuff::Mode porterDuffMode = static_cast<SkPorterDuff::Mode>(porterDuffModeHandle); - SkXfermode::Mode mode = SkPorterDuff::ToXfermodeMode(porterDuffMode); - SkiaShader* skiaShader = new SkiaComposeShader(shaderA, shaderB, mode, shader); - return reinterpret_cast<jlong>(skiaShader); -#else - return NULL; -#endif -} - -static jlong ComposeShader_postCreate1(JNIEnv* env, jobject o, jlong shaderHandle, - jlong shaderAHandle, jlong shaderBHandle, jlong modeHandle) { -#ifdef USE_OPENGL_RENDERER - SkShader* shader = reinterpret_cast<SkShader *>(shaderHandle); - SkiaShader* shaderA = reinterpret_cast<SkiaShader *>(shaderAHandle); - SkiaShader* shaderB = reinterpret_cast<SkiaShader *>(shaderBHandle); - SkXfermode* mode = reinterpret_cast<SkXfermode *>(modeHandle); - SkXfermode::Mode skiaMode; - if (!SkXfermode::AsMode(mode, &skiaMode)) { - // TODO: Support other modes - skiaMode = SkXfermode::kSrcOver_Mode; - } - SkiaShader* skiaShader = new SkiaComposeShader(shaderA, shaderB, skiaMode, shader); - return reinterpret_cast<jlong>(skiaShader); -#else - return NULL; -#endif -} - /////////////////////////////////////////////////////////////////////////////////////////////// static JNINativeMethod gColorMethods[] = { @@ -518,41 +238,32 @@ static JNINativeMethod gColorMethods[] = { }; static JNINativeMethod gShaderMethods[] = { - { "nativeDestructor", "(JJ)V", (void*)Shader_destructor }, - { "nativeSetLocalMatrix", "(JJJ)V", (void*)Shader_setLocalMatrix } + { "nativeDestructor", "(J)V", (void*)Shader_destructor }, + { "nativeSetLocalMatrix", "(JJ)V", (void*)Shader_setLocalMatrix } }; static JNINativeMethod gBitmapShaderMethods[] = { { "nativeCreate", "(JII)J", (void*)BitmapShader_constructor }, - { "nativePostCreate", "(JJII)J", (void*)BitmapShader_postConstructor } }; static JNINativeMethod gLinearGradientMethods[] = { { "nativeCreate1", "(FFFF[I[FI)J", (void*)LinearGradient_create1 }, { "nativeCreate2", "(FFFFIII)J", (void*)LinearGradient_create2 }, - { "nativePostCreate1", "(JFFFF[I[FI)J", (void*)LinearGradient_postCreate1 }, - { "nativePostCreate2", "(JFFFFIII)J", (void*)LinearGradient_postCreate2 } }; static JNINativeMethod gRadialGradientMethods[] = { { "nativeCreate1", "(FFF[I[FI)J", (void*)RadialGradient_create1 }, { "nativeCreate2", "(FFFIII)J", (void*)RadialGradient_create2 }, - { "nativePostCreate1", "(JFFF[I[FI)J", (void*)RadialGradient_postCreate1 }, - { "nativePostCreate2", "(JFFFIII)J", (void*)RadialGradient_postCreate2 } }; static JNINativeMethod gSweepGradientMethods[] = { { "nativeCreate1", "(FF[I[F)J", (void*)SweepGradient_create1 }, { "nativeCreate2", "(FFII)J", (void*)SweepGradient_create2 }, - { "nativePostCreate1", "(JFF[I[F)J", (void*)SweepGradient_postCreate1 }, - { "nativePostCreate2", "(JFFII)J", (void*)SweepGradient_postCreate2 } }; static JNINativeMethod gComposeShaderMethods[] = { { "nativeCreate1", "(JJJ)J", (void*)ComposeShader_create1 }, { "nativeCreate2", "(JJI)J", (void*)ComposeShader_create2 }, - { "nativePostCreate1", "(JJJJ)J", (void*)ComposeShader_postCreate1 }, - { "nativePostCreate2", "(JJJI)J", (void*)ComposeShader_postCreate2 } }; #include <android_runtime/AndroidRuntime.h> diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp index 0d2df80..7935329 100644 --- a/core/jni/android_hardware_camera2_CameraMetadata.cpp +++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp @@ -39,6 +39,9 @@ #include <nativehelper/ScopedUtfChars.h> #include <nativehelper/ScopedPrimitiveArray.h> +#include <sys/types.h> // for socketpair +#include <sys/socket.h> // for socketpair + #if defined(LOG_NNDEBUG) #if !LOG_NNDEBUG #define ALOGVV ALOGV @@ -351,6 +354,119 @@ static void CameraMetadata_writeValues(JNIEnv *env, jobject thiz, jint tag, jbyt } } +struct DumpMetadataParams { + int writeFd; + const CameraMetadata* metadata; +}; + +static void* CameraMetadata_writeMetadataThread(void* arg) { + DumpMetadataParams* p = static_cast<DumpMetadataParams*>(arg); + + /* + * Write the dumped data, and close the writing side FD. + */ + p->metadata->dump(p->writeFd, /*verbosity*/2); + + if (close(p->writeFd) < 0) { + ALOGE("%s: Failed to close writeFd (errno = %#x, message = '%s')", + __FUNCTION__, errno, strerror(errno)); + } + + return NULL; +} + +static void CameraMetadata_dump(JNIEnv *env, jobject thiz) { + ALOGV("%s", __FUNCTION__); + CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz); + if (metadata == NULL) { + return; + } + + /* + * Create a socket pair for local streaming read/writes. + * + * The metadata will be dumped into the write side, + * and then read back out (and logged) via the read side. + */ + + int writeFd, readFd; + { + + int sv[2]; + if (socketpair(AF_LOCAL, SOCK_STREAM, /*protocol*/0, &sv[0]) < 0) { + jniThrowExceptionFmt(env, "java/io/IOException", + "Failed to create socketpair (errno = %#x, message = '%s')", + errno, strerror(errno)); + return; + } + writeFd = sv[0]; + readFd = sv[1]; + } + + /* + * Create a thread for doing the writing. + * + * The reading and writing must be concurrent, otherwise + * the write will block forever once it exhausts the capped + * buffer size (from getsockopt). + */ + pthread_t writeThread; + DumpMetadataParams params = { + writeFd, + metadata + }; + + { + int threadRet = pthread_create(&writeThread, /*attr*/NULL, + CameraMetadata_writeMetadataThread, (void*)¶ms); + + if (threadRet != 0) { + close(writeFd); + + jniThrowExceptionFmt(env, "java/io/IOException", + "Failed to create thread for writing (errno = %#x, message = '%s')", + threadRet, strerror(threadRet)); + } + } + + /* + * Read out a byte until stream is complete. Write completed lines + * to ALOG. + */ + { + char out[] = {'\0', '\0'}; // large enough to append as a string + String8 logLine; + + // Read one byte at a time! Very slow but avoids complicated \n scanning. + ssize_t res; + while ((res = TEMP_FAILURE_RETRY(read(readFd, &out[0], /*count*/1))) > 0) { + if (out[0] == '\n') { + ALOGD("%s", logLine.string()); + logLine.clear(); + } else { + logLine.append(out); + } + } + + if (res < 0) { + jniThrowExceptionFmt(env, "java/io/IOException", + "Failed to read from fd (errno = %#x, message = '%s')", + errno, strerror(errno)); + //return; + } else if (!logLine.isEmpty()) { + ALOGD("%s", logLine.string()); + } + } + + int res; + + // Join until thread finishes. Ensures params/metadata is valid until then. + if ((res = pthread_join(writeThread, /*retval*/NULL)) != 0) { + ALOGE("%s: Failed to join thread (errno = %#x, message = '%s')", + __FUNCTION__, res, strerror(res)); + } +} + static void CameraMetadata_readFromParcel(JNIEnv *env, jobject thiz, jobject parcel) { ALOGV("%s", __FUNCTION__); CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz); @@ -436,6 +552,9 @@ static JNINativeMethod gCameraMetadataMethods[] = { { "nativeWriteValues", "(I[B)V", (void *)CameraMetadata_writeValues }, + { "nativeDump", + "()V", + (void *)CameraMetadata_dump }, // Parcelable interface { "nativeReadFromParcel", "(Landroid/os/Parcel;)V", diff --git a/media/jni/android_media_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp index 860d896..7b686e7 100644 --- a/media/jni/android_media_DngCreator.cpp +++ b/core/jni/android_hardware_camera2_DngCreator.cpp @@ -54,7 +54,7 @@ using namespace img_utils; return; \ } -#define ANDROID_MEDIA_DNGCREATOR_CTX_JNI_ID "mNativeContext" +#define ANDROID_DNGCREATOR_CTX_JNI_ID "mNativeContext" static struct { jfieldID mNativeContext; @@ -163,9 +163,10 @@ static void DngCreator_nativeClassInit(JNIEnv* env, jclass clazz) { ALOGV("%s:", __FUNCTION__); gDngCreatorClassInfo.mNativeContext = env->GetFieldID(clazz, - ANDROID_MEDIA_DNGCREATOR_CTX_JNI_ID, "J"); + ANDROID_DNGCREATOR_CTX_JNI_ID, "J"); LOG_ALWAYS_FATAL_IF(gDngCreatorClassInfo.mNativeContext == NULL, - "can't find android/media/DngCreator.%s", ANDROID_MEDIA_DNGCREATOR_CTX_JNI_ID); + "can't find android/hardware/camera2/DngCreator.%s", + ANDROID_DNGCREATOR_CTX_JNI_ID); jclass outputStreamClazz = env->FindClass("java/io/OutputStream"); LOG_ALWAYS_FATAL_IF(outputStreamClazz == NULL, "Can't find java/io/OutputStream class"); @@ -766,7 +767,8 @@ static JNINativeMethod gDngCreatorMethods[] = { (void*) DngCreator_nativeWriteInputStream}, }; -int register_android_media_DngCreator(JNIEnv *env) { +int register_android_hardware_camera2_DngCreator(JNIEnv *env) { return AndroidRuntime::registerNativeMethods(env, - "android/media/DngCreator", gDngCreatorMethods, NELEM(gDngCreatorMethods)); + "android/hardware/camera2/DngCreator", gDngCreatorMethods, + NELEM(gDngCreatorMethods)); } diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 27d3f39..c5dd06f 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -45,7 +45,6 @@ #include <DisplayListRenderer.h> #include <LayerRenderer.h> #include <OpenGLRenderer.h> -#include <SkiaShader.h> #include <Stencil.h> #include <Rect.h> #include <RenderNode.h> @@ -85,8 +84,6 @@ using namespace uirenderer; #define RENDERER_LOGD(...) #endif -#define MODIFIER_SHADER 2 - // ---------------------------------------------------------------------------- static struct { @@ -616,24 +613,6 @@ static void android_view_GLES20Canvas_drawLines(JNIEnv* env, jobject clazz, } // ---------------------------------------------------------------------------- -// Shaders and color filters -// ---------------------------------------------------------------------------- - -static void android_view_GLES20Canvas_resetModifiers(JNIEnv* env, jobject clazz, - jlong rendererPtr, jint modifiers) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); - if (modifiers & MODIFIER_SHADER) renderer->resetShader(); -} - -static void android_view_GLES20Canvas_setupShader(JNIEnv* env, jobject clazz, - jlong rendererPtr, jlong shaderPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); - SkiaShader* shader = reinterpret_cast<SkiaShader*>(shaderPtr); - renderer->setupShader(shader); -} - - -// ---------------------------------------------------------------------------- // Draw filters // ---------------------------------------------------------------------------- @@ -1091,9 +1070,6 @@ static JNINativeMethod gMethods[] = { { "nDrawPath", "(JJJ)V", (void*) android_view_GLES20Canvas_drawPath }, { "nDrawLines", "(J[FIIJ)V", (void*) android_view_GLES20Canvas_drawLines }, - { "nResetModifiers", "(JI)V", (void*) android_view_GLES20Canvas_resetModifiers }, - { "nSetupShader", "(JJ)V", (void*) android_view_GLES20Canvas_setupShader }, - { "nSetupPaintFilter", "(JII)V", (void*) android_view_GLES20Canvas_setupPaintFilter }, { "nResetPaintFilter", "(J)V", (void*) android_view_GLES20Canvas_resetPaintFilter }, diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 48fb729..5bc0f62 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -299,6 +299,12 @@ static void android_view_ThreadedRenderer_fence(JNIEnv* env, jobject clazz, proxy->fence(); } +static void android_view_ThreadedRenderer_notifyFramePending(JNIEnv* env, jobject clazz, + jlong proxyPtr) { + RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); + proxy->notifyFramePending(); +} + #endif // ---------------------------------------------------------------------------- @@ -329,6 +335,7 @@ static JNINativeMethod gMethods[] = { { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto }, { "nDestroyLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_destroyLayer }, { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence }, + { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending }, #endif }; diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00000_qntm_alpha.png Binary files differdeleted file mode 100644 index 1880a15..0000000 --- a/core/res/res/drawable-hdpi/btn_check_anim_00000_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00001_qntm_alpha.png Binary files differdeleted file mode 100644 index aecb4d2..0000000 --- a/core/res/res/drawable-hdpi/btn_check_anim_00001_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00002_qntm_alpha.png Binary files differdeleted file mode 100644 index 8401f91..0000000 --- a/core/res/res/drawable-hdpi/btn_check_anim_00002_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00003_qntm_alpha.png Binary files differdeleted file mode 100644 index 5832865..0000000 --- a/core/res/res/drawable-hdpi/btn_check_anim_00003_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00004_qntm_alpha.png Binary files differdeleted file mode 100644 index 6d14962..0000000 --- a/core/res/res/drawable-hdpi/btn_check_anim_00004_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00005_qntm_alpha.png Binary files differdeleted file mode 100644 index aee057c..0000000 --- a/core/res/res/drawable-hdpi/btn_check_anim_00005_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00006_qntm_alpha.png Binary files differdeleted file mode 100644 index fb5801e..0000000 --- a/core/res/res/drawable-hdpi/btn_check_anim_00006_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00007_qntm_alpha.png Binary files differdeleted file mode 100644 index fdb5271..0000000 --- a/core/res/res/drawable-hdpi/btn_check_anim_00007_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00008_qntm_alpha.png Binary files differdeleted file mode 100644 index b8c7397..0000000 --- a/core/res/res/drawable-hdpi/btn_check_anim_00008_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00009_qntm_alpha.png Binary files differdeleted file mode 100644 index d0395a8..0000000 --- a/core/res/res/drawable-hdpi/btn_check_anim_00009_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00010_qntm_alpha.png Binary files differdeleted file mode 100644 index 59bb437..0000000 --- a/core/res/res/drawable-hdpi/btn_check_anim_00010_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00011_qntm_alpha.png Binary files differdeleted file mode 100644 index c053b90..0000000 --- a/core/res/res/drawable-hdpi/btn_check_anim_00011_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00012_qntm_alpha.png Binary files differdeleted file mode 100644 index eb30a79..0000000 --- a/core/res/res/drawable-hdpi/btn_check_anim_00012_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00013_qntm_alpha.png Binary files differdeleted file mode 100644 index 1af0bff..0000000 --- a/core/res/res/drawable-hdpi/btn_check_anim_00013_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00014_qntm_alpha.png Binary files differdeleted file mode 100644 index 3b36e7d..0000000 --- a/core/res/res/drawable-hdpi/btn_check_anim_00014_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00015_qntm_alpha.png Binary files differdeleted file mode 100644 index c12d20a..0000000 --- a/core/res/res/drawable-hdpi/btn_check_anim_00015_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_check_off_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_off_qntm_alpha.png Binary files differdeleted file mode 100644 index 5bc1d90..0000000 --- a/core/res/res/drawable-hdpi/btn_check_off_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_check_on_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_on_qntm_alpha.png Binary files differdeleted file mode 100644 index e5de2c1..0000000 --- a/core/res/res/drawable-hdpi/btn_check_on_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_000.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_000.png Binary files differnew file mode 100644 index 0000000..3cb4073 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_000.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_001.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_001.png Binary files differnew file mode 100644 index 0000000..8fd1480 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_001.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_002.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_002.png Binary files differnew file mode 100644 index 0000000..d35b579 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_002.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_003.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_003.png Binary files differnew file mode 100644 index 0000000..543c6bc --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_003.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_004.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_004.png Binary files differnew file mode 100644 index 0000000..4fc3c40 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_004.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_005.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_005.png Binary files differnew file mode 100644 index 0000000..c184535 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_005.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_006.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_006.png Binary files differnew file mode 100644 index 0000000..9f9dd43 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_006.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_007.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_007.png Binary files differnew file mode 100644 index 0000000..8c629ce --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_007.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_008.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_008.png Binary files differnew file mode 100644 index 0000000..81134b5 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_008.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_009.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_009.png Binary files differnew file mode 100644 index 0000000..baa5860 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_009.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_010.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_010.png Binary files differnew file mode 100644 index 0000000..d7e28366 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_010.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_011.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_011.png Binary files differnew file mode 100644 index 0000000..6f24795 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_011.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_012.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_012.png Binary files differnew file mode 100644 index 0000000..22f997d --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_012.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_013.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_013.png Binary files differnew file mode 100644 index 0000000..85f4471 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_013.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_014.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_014.png Binary files differnew file mode 100644 index 0000000..ad483c9 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_014.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_015.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_015.png Binary files differnew file mode 100644 index 0000000..f24c2fb --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_015.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_000.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_000.png Binary files differnew file mode 100644 index 0000000..7a9e9bd --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_000.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_001.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_001.png Binary files differnew file mode 100644 index 0000000..af04902 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_001.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_002.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_002.png Binary files differnew file mode 100644 index 0000000..32a6e94 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_002.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_003.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_003.png Binary files differnew file mode 100644 index 0000000..c1b4b37 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_003.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_004.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_004.png Binary files differnew file mode 100644 index 0000000..34d3ade --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_004.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_005.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_005.png Binary files differnew file mode 100644 index 0000000..3d5db53 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_005.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_006.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_006.png Binary files differnew file mode 100644 index 0000000..ea35437 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_006.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_007.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_007.png Binary files differnew file mode 100644 index 0000000..48744f8 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_007.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_008.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_008.png Binary files differnew file mode 100644 index 0000000..f654517 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_008.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_009.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_009.png Binary files differnew file mode 100644 index 0000000..16f959a --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_009.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_010.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_010.png Binary files differnew file mode 100644 index 0000000..98c754b --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_010.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_011.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_011.png Binary files differnew file mode 100644 index 0000000..5827dc2 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_011.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_012.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_012.png Binary files differnew file mode 100644 index 0000000..9850d74 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_012.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_013.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_013.png Binary files differnew file mode 100644 index 0000000..03ab06b --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_013.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_014.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_014.png Binary files differnew file mode 100644 index 0000000..11cdd88 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_014.png diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_015.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_015.png Binary files differnew file mode 100644 index 0000000..874edbf --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_015.png diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00000_qntm_alpha.png Binary files differdeleted file mode 100644 index 882365b..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_anim_00000_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00001_qntm_alpha.png Binary files differdeleted file mode 100644 index f6c7094..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_anim_00001_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00002_qntm_alpha.png Binary files differdeleted file mode 100644 index 0e326c9..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_anim_00002_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00003_qntm_alpha.png Binary files differdeleted file mode 100644 index 8bf1170..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_anim_00003_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00004_qntm_alpha.png Binary files differdeleted file mode 100644 index cedb66e..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_anim_00004_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00005_qntm_alpha.png Binary files differdeleted file mode 100644 index 257d7ba..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_anim_00005_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00006_qntm_alpha.png Binary files differdeleted file mode 100644 index e07b36e..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_anim_00006_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00007_qntm_alpha.png Binary files differdeleted file mode 100644 index ef94200..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_anim_00007_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00008_qntm_alpha.png Binary files differdeleted file mode 100644 index ad67004..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_anim_00008_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00009_qntm_alpha.png Binary files differdeleted file mode 100644 index 50796e2..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_anim_00009_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00010_qntm_alpha.png Binary files differdeleted file mode 100644 index ba7be9e..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_anim_00010_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00011_qntm_alpha.png Binary files differdeleted file mode 100644 index bdbfe78..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_anim_00011_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00012_qntm_alpha.png Binary files differdeleted file mode 100644 index fe89951..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_anim_00012_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00013_qntm_alpha.png Binary files differdeleted file mode 100644 index 840c88f..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_anim_00013_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00014_qntm_alpha.png Binary files differdeleted file mode 100644 index 621d1d2..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_anim_00014_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00015_qntm_alpha.png Binary files differdeleted file mode 100644 index fd8be89..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_anim_00015_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_off_pressed_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_off_pressed_qntm_alpha.png Binary files differdeleted file mode 100644 index 7bef530..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_off_pressed_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_off_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_off_qntm_alpha.png Binary files differdeleted file mode 100644 index ae50dd5..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_off_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_on_pressed_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_on_pressed_qntm_alpha.png Binary files differdeleted file mode 100644 index 0678dbb..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_on_pressed_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_on_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_on_qntm_alpha.png Binary files differdeleted file mode 100644 index f332925..0000000 --- a/core/res/res/drawable-hdpi/btn_radio_on_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_000.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_000.png Binary files differnew file mode 100644 index 0000000..da88e98 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_000.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_001.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_001.png Binary files differnew file mode 100644 index 0000000..907d92d --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_001.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_002.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_002.png Binary files differnew file mode 100644 index 0000000..9d24dc1 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_002.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_003.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_003.png Binary files differnew file mode 100644 index 0000000..8aa2605 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_003.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_004.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_004.png Binary files differnew file mode 100644 index 0000000..b4cdf02 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_004.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_005.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_005.png Binary files differnew file mode 100644 index 0000000..0724ed7 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_005.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_006.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_006.png Binary files differnew file mode 100644 index 0000000..c9bd4e3 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_006.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_007.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_007.png Binary files differnew file mode 100644 index 0000000..5630ec3 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_007.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_008.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_008.png Binary files differnew file mode 100644 index 0000000..4bf666c --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_008.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_009.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_009.png Binary files differnew file mode 100644 index 0000000..dffaa07 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_009.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_010.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_010.png Binary files differnew file mode 100644 index 0000000..5f86e18 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_010.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_011.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_011.png Binary files differnew file mode 100644 index 0000000..9b50aef --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_011.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_012.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_012.png Binary files differnew file mode 100644 index 0000000..1cf5e7f --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_012.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_013.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_013.png Binary files differnew file mode 100644 index 0000000..2bb641a --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_013.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_014.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_014.png Binary files differnew file mode 100644 index 0000000..08e7485 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_014.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_015.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_015.png Binary files differnew file mode 100644 index 0000000..519b5a3 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_015.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_000.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_000.png Binary files differnew file mode 100644 index 0000000..0d3e1e7 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_000.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_001.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_001.png Binary files differnew file mode 100644 index 0000000..88c4a9e --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_001.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_002.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_002.png Binary files differnew file mode 100644 index 0000000..8fa2e88 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_002.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_003.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_003.png Binary files differnew file mode 100644 index 0000000..53dd9d7 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_003.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_004.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_004.png Binary files differnew file mode 100644 index 0000000..e235195 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_004.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_005.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_005.png Binary files differnew file mode 100644 index 0000000..1721284 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_005.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_006.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_006.png Binary files differnew file mode 100644 index 0000000..31819fa --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_006.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_007.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_007.png Binary files differnew file mode 100644 index 0000000..5de44b9 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_007.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_008.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_008.png Binary files differnew file mode 100644 index 0000000..aa20f65 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_008.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_009.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_009.png Binary files differnew file mode 100644 index 0000000..c379ba7 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_009.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_010.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_010.png Binary files differnew file mode 100644 index 0000000..e23b410 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_010.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_011.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_011.png Binary files differnew file mode 100644 index 0000000..a9543dc --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_011.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_012.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_012.png Binary files differnew file mode 100644 index 0000000..2473b78 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_012.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_013.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_013.png Binary files differnew file mode 100644 index 0000000..b4acc9c --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_013.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_014.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_014.png Binary files differnew file mode 100644 index 0000000..c9cf344 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_014.png diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_015.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_015.png Binary files differnew file mode 100644 index 0000000..a8c390e --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_015.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_000.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_000.png Binary files differnew file mode 100644 index 0000000..c54f8d7 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_000.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_001.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_001.png Binary files differnew file mode 100644 index 0000000..e062f61 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_001.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_002.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_002.png Binary files differnew file mode 100644 index 0000000..7737646 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_002.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_003.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_003.png Binary files differnew file mode 100644 index 0000000..65ff45e --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_003.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_004.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_004.png Binary files differnew file mode 100644 index 0000000..11aaec0 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_004.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_005.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_005.png Binary files differnew file mode 100644 index 0000000..9e1b60f --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_005.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_006.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_006.png Binary files differnew file mode 100644 index 0000000..1e45687 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_006.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_007.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_007.png Binary files differnew file mode 100644 index 0000000..1e45687 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_007.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_008.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_008.png Binary files differnew file mode 100644 index 0000000..6c48456 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_008.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_009.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_009.png Binary files differnew file mode 100644 index 0000000..a4d084b --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_009.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_010.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_010.png Binary files differnew file mode 100644 index 0000000..1e1a1b0 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_010.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_011.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_011.png Binary files differnew file mode 100644 index 0000000..1e1a1b0 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_011.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_012.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_012.png Binary files differnew file mode 100644 index 0000000..1e1a1b0 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_012.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_013.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_013.png Binary files differnew file mode 100644 index 0000000..1e1a1b0 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_013.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_014.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_014.png Binary files differnew file mode 100644 index 0000000..1e1a1b0 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_014.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_000.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_000.png Binary files differnew file mode 100644 index 0000000..cf09f97 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_000.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_001.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_001.png Binary files differnew file mode 100644 index 0000000..3218e66 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_001.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_002.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_002.png Binary files differnew file mode 100644 index 0000000..0acff03 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_002.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_003.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_003.png Binary files differnew file mode 100644 index 0000000..c93adf4 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_003.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_004.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_004.png Binary files differnew file mode 100644 index 0000000..5d8ddc96 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_004.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_005.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_005.png Binary files differnew file mode 100644 index 0000000..47206a4 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_005.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_006.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_006.png Binary files differnew file mode 100644 index 0000000..7d6a91f --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_006.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_007.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_007.png Binary files differnew file mode 100644 index 0000000..e062f61 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_007.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_008.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_008.png Binary files differnew file mode 100644 index 0000000..b0f0dde --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_008.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_009.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_009.png Binary files differnew file mode 100644 index 0000000..c54f8d7 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_009.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_010.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_010.png Binary files differnew file mode 100644 index 0000000..c54f8d7 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_010.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_011.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_011.png Binary files differnew file mode 100644 index 0000000..c54f8d7 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_011.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_012.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_012.png Binary files differnew file mode 100644 index 0000000..c54f8d7 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_012.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_013.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_013.png Binary files differnew file mode 100644 index 0000000..c54f8d7 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_013.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_014.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_014.png Binary files differnew file mode 100644 index 0000000..c54f8d7 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_014.png diff --git a/core/res/res/drawable-hdpi/btn_toggle_indicator_qntm_alpha.9.png b/core/res/res/drawable-hdpi/btn_toggle_indicator_qntm_alpha.9.png Binary files differnew file mode 100644 index 0000000..68e17ad --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_toggle_indicator_qntm_alpha.9.png diff --git a/core/res/res/drawable-hdpi/btn_toggle_qntm_alpha.9.png b/core/res/res/drawable-hdpi/btn_toggle_qntm_alpha.9.png Binary files differnew file mode 100644 index 0000000..879d9c2 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_toggle_qntm_alpha.9.png diff --git a/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_000.png b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_000.png Binary files differnew file mode 100644 index 0000000..281923e --- /dev/null +++ b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_000.png diff --git a/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_001.png b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_001.png Binary files differnew file mode 100644 index 0000000..e91d4fb --- /dev/null +++ b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_001.png diff --git a/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_002.png b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_002.png Binary files differnew file mode 100644 index 0000000..15baded --- /dev/null +++ b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_002.png diff --git a/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_003.png b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_003.png Binary files differnew file mode 100644 index 0000000..3d5899f --- /dev/null +++ b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_003.png diff --git a/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_004.png b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_004.png Binary files differnew file mode 100644 index 0000000..e2277bd --- /dev/null +++ b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_004.png diff --git a/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_005.png b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_005.png Binary files differnew file mode 100644 index 0000000..b502e22 --- /dev/null +++ b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_005.png diff --git a/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_000.png b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_000.png Binary files differnew file mode 100644 index 0000000..a70be2c --- /dev/null +++ b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_000.png diff --git a/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_001.png b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_001.png Binary files differnew file mode 100644 index 0000000..9442316 --- /dev/null +++ b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_001.png diff --git a/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_002.png b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_002.png Binary files differnew file mode 100644 index 0000000..33db4a88 --- /dev/null +++ b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_002.png diff --git a/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_003.png b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_003.png Binary files differnew file mode 100644 index 0000000..4e1cd16 --- /dev/null +++ b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_003.png diff --git a/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_004.png b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_004.png Binary files differnew file mode 100644 index 0000000..d5254f4 --- /dev/null +++ b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_004.png diff --git a/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_005.png b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_005.png Binary files differnew file mode 100644 index 0000000..7aa0a3e --- /dev/null +++ b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_005.png diff --git a/core/res/res/drawable-hdpi/switch_off_qntm_alpha.9.png b/core/res/res/drawable-hdpi/switch_off_qntm_alpha.9.png Binary files differdeleted file mode 100644 index 73e8f1c..0000000 --- a/core/res/res/drawable-hdpi/switch_off_qntm_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/switch_on_qntm_alpha.9.png b/core/res/res/drawable-hdpi/switch_on_qntm_alpha.9.png Binary files differdeleted file mode 100644 index ff6affe..0000000 --- a/core/res/res/drawable-hdpi/switch_on_qntm_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/switch_track_qntm_alpha.9.png b/core/res/res/drawable-hdpi/switch_track_qntm_alpha.9.png Binary files differindex b11de9e..ac1fc23 100644 --- a/core/res/res/drawable-hdpi/switch_track_qntm_alpha.9.png +++ b/core/res/res/drawable-hdpi/switch_track_qntm_alpha.9.png diff --git a/core/res/res/drawable-hdpi/text_select_handle_left_qntm_alpha.png b/core/res/res/drawable-hdpi/text_select_handle_left_qntm_alpha.png Binary files differindex 598b98c..9cdc25b 100644 --- a/core/res/res/drawable-hdpi/text_select_handle_left_qntm_alpha.png +++ b/core/res/res/drawable-hdpi/text_select_handle_left_qntm_alpha.png diff --git a/core/res/res/drawable-hdpi/text_select_handle_right_qntm_alpha.png b/core/res/res/drawable-hdpi/text_select_handle_right_qntm_alpha.png Binary files differindex 79fe7c5..276d480 100644 --- a/core/res/res/drawable-hdpi/text_select_handle_right_qntm_alpha.png +++ b/core/res/res/drawable-hdpi/text_select_handle_right_qntm_alpha.png diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00000_qntm_alpha.png Binary files differdeleted file mode 100644 index 0f44ff9..0000000 --- a/core/res/res/drawable-mdpi/btn_check_anim_00000_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00001_qntm_alpha.png Binary files differdeleted file mode 100644 index 9d5dda0..0000000 --- a/core/res/res/drawable-mdpi/btn_check_anim_00001_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00002_qntm_alpha.png Binary files differdeleted file mode 100644 index e4ce802..0000000 --- a/core/res/res/drawable-mdpi/btn_check_anim_00002_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00003_qntm_alpha.png Binary files differdeleted file mode 100644 index d1806ac..0000000 --- a/core/res/res/drawable-mdpi/btn_check_anim_00003_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00004_qntm_alpha.png Binary files differdeleted file mode 100644 index ab9315b..0000000 --- a/core/res/res/drawable-mdpi/btn_check_anim_00004_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00005_qntm_alpha.png Binary files differdeleted file mode 100644 index 46e90e6..0000000 --- a/core/res/res/drawable-mdpi/btn_check_anim_00005_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00006_qntm_alpha.png Binary files differdeleted file mode 100644 index e8c56ff..0000000 --- a/core/res/res/drawable-mdpi/btn_check_anim_00006_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00007_qntm_alpha.png Binary files differdeleted file mode 100644 index 59dcb7e..0000000 --- a/core/res/res/drawable-mdpi/btn_check_anim_00007_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00008_qntm_alpha.png Binary files differdeleted file mode 100644 index e9bd4a2..0000000 --- a/core/res/res/drawable-mdpi/btn_check_anim_00008_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00009_qntm_alpha.png Binary files differdeleted file mode 100644 index 1d05037..0000000 --- a/core/res/res/drawable-mdpi/btn_check_anim_00009_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00010_qntm_alpha.png Binary files differdeleted file mode 100644 index 91b40de..0000000 --- a/core/res/res/drawable-mdpi/btn_check_anim_00010_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00011_qntm_alpha.png Binary files differdeleted file mode 100644 index c531cab..0000000 --- a/core/res/res/drawable-mdpi/btn_check_anim_00011_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00012_qntm_alpha.png Binary files differdeleted file mode 100644 index 11bb387..0000000 --- a/core/res/res/drawable-mdpi/btn_check_anim_00012_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00013_qntm_alpha.png Binary files differdeleted file mode 100644 index 8843210..0000000 --- a/core/res/res/drawable-mdpi/btn_check_anim_00013_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00014_qntm_alpha.png Binary files differdeleted file mode 100644 index 6ff2f3d..0000000 --- a/core/res/res/drawable-mdpi/btn_check_anim_00014_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00015_qntm_alpha.png Binary files differdeleted file mode 100644 index a03c1e2..0000000 --- a/core/res/res/drawable-mdpi/btn_check_anim_00015_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_check_off_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_off_qntm_alpha.png Binary files differdeleted file mode 100644 index 2ab6b7f..0000000 --- a/core/res/res/drawable-mdpi/btn_check_off_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_check_on_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_on_qntm_alpha.png Binary files differdeleted file mode 100644 index 2211d83..0000000 --- a/core/res/res/drawable-mdpi/btn_check_on_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_000.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_000.png Binary files differnew file mode 100644 index 0000000..9759818 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_000.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_001.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_001.png Binary files differnew file mode 100644 index 0000000..4eb2c4f --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_001.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_002.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_002.png Binary files differnew file mode 100644 index 0000000..e6d6b42 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_002.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_003.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_003.png Binary files differnew file mode 100644 index 0000000..03cb23a --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_003.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_004.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_004.png Binary files differnew file mode 100644 index 0000000..bfe3c3d --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_004.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_005.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_005.png Binary files differnew file mode 100644 index 0000000..65bdf42 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_005.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_006.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_006.png Binary files differnew file mode 100644 index 0000000..44f9614b --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_006.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_007.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_007.png Binary files differnew file mode 100644 index 0000000..cf8ec38 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_007.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_008.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_008.png Binary files differnew file mode 100644 index 0000000..4d624b3 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_008.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_009.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_009.png Binary files differnew file mode 100644 index 0000000..7c4eb7f --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_009.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_010.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_010.png Binary files differnew file mode 100644 index 0000000..e90dd31 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_010.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_011.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_011.png Binary files differnew file mode 100644 index 0000000..831c0e8 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_011.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_012.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_012.png Binary files differnew file mode 100644 index 0000000..7355dfd --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_012.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_013.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_013.png Binary files differnew file mode 100644 index 0000000..be71a69 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_013.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_014.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_014.png Binary files differnew file mode 100644 index 0000000..a4a185b --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_014.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_015.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_015.png Binary files differnew file mode 100644 index 0000000..8d0386f --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_015.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_000.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_000.png Binary files differnew file mode 100644 index 0000000..70793c4 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_000.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_001.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_001.png Binary files differnew file mode 100644 index 0000000..632082b --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_001.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_002.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_002.png Binary files differnew file mode 100644 index 0000000..e7fc5fb --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_002.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_003.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_003.png Binary files differnew file mode 100644 index 0000000..91a0a33 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_003.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_004.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_004.png Binary files differnew file mode 100644 index 0000000..3bd90d6 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_004.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_005.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_005.png Binary files differnew file mode 100644 index 0000000..5ac39ec --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_005.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_006.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_006.png Binary files differnew file mode 100644 index 0000000..4181983 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_006.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_007.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_007.png Binary files differnew file mode 100644 index 0000000..c8b04df --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_007.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_008.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_008.png Binary files differnew file mode 100644 index 0000000..b7b3a9f --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_008.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_009.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_009.png Binary files differnew file mode 100644 index 0000000..62bc4ed --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_009.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_010.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_010.png Binary files differnew file mode 100644 index 0000000..ac463ad --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_010.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_011.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_011.png Binary files differnew file mode 100644 index 0000000..12b605d --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_011.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_012.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_012.png Binary files differnew file mode 100644 index 0000000..63a3c6a --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_012.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_013.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_013.png Binary files differnew file mode 100644 index 0000000..17660c4 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_013.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_014.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_014.png Binary files differnew file mode 100644 index 0000000..7d9de3d --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_014.png diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_015.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_015.png Binary files differnew file mode 100644 index 0000000..8aa1be2 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_015.png diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00000_qntm_alpha.png Binary files differdeleted file mode 100644 index 0a22e1a..0000000 --- a/core/res/res/drawable-mdpi/btn_radio_anim_00000_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00001_qntm_alpha.png Binary files differdeleted file mode 100644 index 2e2469c..0000000 --- a/core/res/res/drawable-mdpi/btn_radio_anim_00001_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00002_qntm_alpha.png Binary files differdeleted file mode 100644 index c1054d9..0000000 --- a/core/res/res/drawable-mdpi/btn_radio_anim_00002_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00003_qntm_alpha.png Binary files differdeleted file mode 100644 index cf8d80a..0000000 --- a/core/res/res/drawable-mdpi/btn_radio_anim_00003_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00004_qntm_alpha.png Binary files differdeleted file mode 100644 index 9d9e870..0000000 --- a/core/res/res/drawable-mdpi/btn_radio_anim_00004_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00005_qntm_alpha.png Binary files differdeleted file mode 100644 index 1bad701..0000000 --- a/core/res/res/drawable-mdpi/btn_radio_anim_00005_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00006_qntm_alpha.png Binary files differdeleted file mode 100644 index a84a54f..0000000 --- a/core/res/res/drawable-mdpi/btn_radio_anim_00006_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00007_qntm_alpha.png Binary files differdeleted file mode 100644 index 4d8050b..0000000 --- a/core/res/res/drawable-mdpi/btn_radio_anim_00007_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00008_qntm_alpha.png Binary files differdeleted file mode 100644 index 374172c..0000000 --- a/core/res/res/drawable-mdpi/btn_radio_anim_00008_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00009_qntm_alpha.png Binary files differdeleted file mode 100644 index 233036e..0000000 --- a/core/res/res/drawable-mdpi/btn_radio_anim_00009_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00010_qntm_alpha.png Binary files differdeleted file mode 100644 index 61d9b58..0000000 --- a/core/res/res/drawable-mdpi/btn_radio_anim_00010_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00011_qntm_alpha.png Binary files differdeleted file mode 100644 index 274e983..0000000 --- a/core/res/res/drawable-mdpi/btn_radio_anim_00011_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00012_qntm_alpha.png Binary files differdeleted file mode 100644 index acf16e5..0000000 --- a/core/res/res/drawable-mdpi/btn_radio_anim_00012_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00013_qntm_alpha.png Binary files differdeleted file mode 100644 index ee48241..0000000 --- a/core/res/res/drawable-mdpi/btn_radio_anim_00013_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00014_qntm_alpha.png Binary files differdeleted file mode 100644 index dbbb736..0000000 --- a/core/res/res/drawable-mdpi/btn_radio_anim_00014_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00015_qntm_alpha.png Binary files differdeleted file mode 100644 index bcabd0d..0000000 --- a/core/res/res/drawable-mdpi/btn_radio_anim_00015_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_radio_off_pressed_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_off_pressed_qntm_alpha.png Binary files differdeleted file mode 100644 index 713fee8..0000000 --- a/core/res/res/drawable-mdpi/btn_radio_off_pressed_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_radio_off_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_off_qntm_alpha.png Binary files differdeleted file mode 100644 index dcb90d0..0000000 --- a/core/res/res/drawable-mdpi/btn_radio_off_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_000.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_000.png Binary files differnew file mode 100644 index 0000000..a2b7fce --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_000.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_001.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_001.png Binary files differnew file mode 100644 index 0000000..fe0d3b1 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_001.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_002.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_002.png Binary files differnew file mode 100644 index 0000000..d66d00d --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_002.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_003.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_003.png Binary files differnew file mode 100644 index 0000000..2f2f5cd --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_003.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_004.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_004.png Binary files differnew file mode 100644 index 0000000..72c9495 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_004.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_005.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_005.png Binary files differnew file mode 100644 index 0000000..7d9090f --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_005.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_006.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_006.png Binary files differnew file mode 100644 index 0000000..c5442e8 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_006.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_007.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_007.png Binary files differnew file mode 100644 index 0000000..ca80cdb --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_007.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_008.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_008.png Binary files differnew file mode 100644 index 0000000..d41a10b --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_008.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_009.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_009.png Binary files differnew file mode 100644 index 0000000..262c838 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_009.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_010.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_010.png Binary files differnew file mode 100644 index 0000000..7f6ea8b --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_010.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_011.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_011.png Binary files differnew file mode 100644 index 0000000..8d50a81 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_011.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_012.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_012.png Binary files differnew file mode 100644 index 0000000..0725a68 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_012.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_013.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_013.png Binary files differnew file mode 100644 index 0000000..6191a4b --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_013.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_014.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_014.png Binary files differnew file mode 100644 index 0000000..1904d74 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_014.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_015.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_015.png Binary files differnew file mode 100644 index 0000000..bec8dda --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_015.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_000.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_000.png Binary files differnew file mode 100644 index 0000000..54ef480 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_000.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_001.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_001.png Binary files differnew file mode 100644 index 0000000..55c5163 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_001.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_002.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_002.png Binary files differnew file mode 100644 index 0000000..0fe2a89 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_002.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_003.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_003.png Binary files differnew file mode 100644 index 0000000..86efab7 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_003.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_004.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_004.png Binary files differnew file mode 100644 index 0000000..c0a5ca5 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_004.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_005.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_005.png Binary files differnew file mode 100644 index 0000000..ec55175 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_005.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_006.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_006.png Binary files differnew file mode 100644 index 0000000..3e4a690 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_006.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_007.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_007.png Binary files differnew file mode 100644 index 0000000..da49734 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_007.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_008.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_008.png Binary files differnew file mode 100644 index 0000000..471cda1 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_008.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_009.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_009.png Binary files differnew file mode 100644 index 0000000..d560262 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_009.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_010.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_010.png Binary files differnew file mode 100644 index 0000000..f6096b4 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_010.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_011.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_011.png Binary files differnew file mode 100644 index 0000000..9e2500b --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_011.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_012.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_012.png Binary files differnew file mode 100644 index 0000000..efbac99 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_012.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_013.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_013.png Binary files differnew file mode 100644 index 0000000..676f0ca --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_013.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_014.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_014.png Binary files differnew file mode 100644 index 0000000..4803157 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_014.png diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_015.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_015.png Binary files differnew file mode 100644 index 0000000..4f8a162 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_015.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_000.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_000.png Binary files differnew file mode 100644 index 0000000..8c3f26c --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_000.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_001.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_001.png Binary files differnew file mode 100644 index 0000000..3617168 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_001.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_002.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_002.png Binary files differnew file mode 100644 index 0000000..e4366f4 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_002.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_003.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_003.png Binary files differnew file mode 100644 index 0000000..ea4533b --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_003.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_004.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_004.png Binary files differnew file mode 100644 index 0000000..94aedbb --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_004.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_005.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_005.png Binary files differnew file mode 100644 index 0000000..ef84578 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_005.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_006.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_006.png Binary files differnew file mode 100644 index 0000000..4de2321 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_006.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_007.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_007.png Binary files differnew file mode 100644 index 0000000..4de2321 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_007.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_008.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_008.png Binary files differnew file mode 100644 index 0000000..d62fbd5 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_008.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_009.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_009.png Binary files differnew file mode 100644 index 0000000..3d87c4e --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_009.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_010.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_010.png Binary files differnew file mode 100644 index 0000000..536ed46 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_010.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_011.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_011.png Binary files differnew file mode 100644 index 0000000..536ed46 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_011.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_012.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_012.png Binary files differnew file mode 100644 index 0000000..536ed46 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_012.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_013.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_013.png Binary files differnew file mode 100644 index 0000000..536ed46 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_013.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_014.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_014.png Binary files differnew file mode 100644 index 0000000..536ed46 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_014.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_000.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_000.png Binary files differnew file mode 100644 index 0000000..f5b660d --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_000.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_001.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_001.png Binary files differnew file mode 100644 index 0000000..9e4db6c --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_001.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_002.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_002.png Binary files differnew file mode 100644 index 0000000..7de2128 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_002.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_003.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_003.png Binary files differnew file mode 100644 index 0000000..1980c2c --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_003.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_004.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_004.png Binary files differnew file mode 100644 index 0000000..6e73ef0 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_004.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_005.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_005.png Binary files differnew file mode 100644 index 0000000..f897392 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_005.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_006.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_006.png Binary files differnew file mode 100644 index 0000000..74a6ebd --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_006.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_007.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_007.png Binary files differnew file mode 100644 index 0000000..3617168 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_007.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_008.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_008.png Binary files differnew file mode 100644 index 0000000..884eb66 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_008.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_009.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_009.png Binary files differnew file mode 100644 index 0000000..8c3f26c --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_009.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_010.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_010.png Binary files differnew file mode 100644 index 0000000..8c3f26c --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_010.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_011.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_011.png Binary files differnew file mode 100644 index 0000000..8c3f26c --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_011.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_012.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_012.png Binary files differnew file mode 100644 index 0000000..8c3f26c --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_012.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_013.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_013.png Binary files differnew file mode 100644 index 0000000..8c3f26c --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_013.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_014.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_014.png Binary files differnew file mode 100644 index 0000000..8c3f26c --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_014.png diff --git a/core/res/res/drawable-mdpi/btn_toggle_indicator_qntm_alpha.9.png b/core/res/res/drawable-mdpi/btn_toggle_indicator_qntm_alpha.9.png Binary files differnew file mode 100644 index 0000000..e5bface --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_toggle_indicator_qntm_alpha.9.png diff --git a/core/res/res/drawable-mdpi/btn_toggle_qntm_alpha.9.png b/core/res/res/drawable-mdpi/btn_toggle_qntm_alpha.9.png Binary files differnew file mode 100644 index 0000000..dca86ea --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_toggle_qntm_alpha.9.png diff --git a/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_000.png b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_000.png Binary files differnew file mode 100644 index 0000000..377a6b4 --- /dev/null +++ b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_000.png diff --git a/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_001.png b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_001.png Binary files differnew file mode 100644 index 0000000..0859f62 --- /dev/null +++ b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_001.png diff --git a/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_002.png b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_002.png Binary files differnew file mode 100644 index 0000000..bf5cdcd --- /dev/null +++ b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_002.png diff --git a/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_003.png b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_003.png Binary files differnew file mode 100644 index 0000000..4cd177d --- /dev/null +++ b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_003.png diff --git a/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_004.png b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_004.png Binary files differnew file mode 100644 index 0000000..dfe39ca --- /dev/null +++ b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_004.png diff --git a/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_005.png b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_005.png Binary files differnew file mode 100644 index 0000000..5d3ab99 --- /dev/null +++ b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_005.png diff --git a/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_000.png b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_000.png Binary files differnew file mode 100644 index 0000000..80922eb --- /dev/null +++ b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_000.png diff --git a/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_001.png b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_001.png Binary files differnew file mode 100644 index 0000000..aa77044 --- /dev/null +++ b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_001.png diff --git a/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_002.png b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_002.png Binary files differnew file mode 100644 index 0000000..7b099db --- /dev/null +++ b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_002.png diff --git a/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_003.png b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_003.png Binary files differnew file mode 100644 index 0000000..088c86a --- /dev/null +++ b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_003.png diff --git a/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_004.png b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_004.png Binary files differnew file mode 100644 index 0000000..3c6b9bc --- /dev/null +++ b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_004.png diff --git a/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_005.png b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_005.png Binary files differnew file mode 100644 index 0000000..adf5100 --- /dev/null +++ b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_005.png diff --git a/core/res/res/drawable-mdpi/switch_off_qntm_alpha.9.png b/core/res/res/drawable-mdpi/switch_off_qntm_alpha.9.png Binary files differdeleted file mode 100644 index 8949b52..0000000 --- a/core/res/res/drawable-mdpi/switch_off_qntm_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/switch_on_qntm_alpha.9.png b/core/res/res/drawable-mdpi/switch_on_qntm_alpha.9.png Binary files differdeleted file mode 100644 index d727683..0000000 --- a/core/res/res/drawable-mdpi/switch_on_qntm_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/switch_track_qntm_alpha.9.png b/core/res/res/drawable-mdpi/switch_track_qntm_alpha.9.png Binary files differindex 8991421..b6538e4 100644 --- a/core/res/res/drawable-mdpi/switch_track_qntm_alpha.9.png +++ b/core/res/res/drawable-mdpi/switch_track_qntm_alpha.9.png diff --git a/core/res/res/drawable-mdpi/text_select_handle_left_qntm_alpha.png b/core/res/res/drawable-mdpi/text_select_handle_left_qntm_alpha.png Binary files differindex 506a186..95c0168 100644 --- a/core/res/res/drawable-mdpi/text_select_handle_left_qntm_alpha.png +++ b/core/res/res/drawable-mdpi/text_select_handle_left_qntm_alpha.png diff --git a/core/res/res/drawable-mdpi/text_select_handle_right_qntm_alpha.png b/core/res/res/drawable-mdpi/text_select_handle_right_qntm_alpha.png Binary files differindex fb0e926..569332a 100644 --- a/core/res/res/drawable-mdpi/text_select_handle_right_qntm_alpha.png +++ b/core/res/res/drawable-mdpi/text_select_handle_right_qntm_alpha.png diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00000_qntm_alpha.png Binary files differdeleted file mode 100644 index 25500e8..0000000 --- a/core/res/res/drawable-xhdpi/btn_check_anim_00000_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00001_qntm_alpha.png Binary files differdeleted file mode 100644 index b136e25..0000000 --- a/core/res/res/drawable-xhdpi/btn_check_anim_00001_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00002_qntm_alpha.png Binary files differdeleted file mode 100644 index 6a94e30..0000000 --- a/core/res/res/drawable-xhdpi/btn_check_anim_00002_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00003_qntm_alpha.png Binary files differdeleted file mode 100644 index d386421..0000000 --- a/core/res/res/drawable-xhdpi/btn_check_anim_00003_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00004_qntm_alpha.png Binary files differdeleted file mode 100644 index c811385..0000000 --- a/core/res/res/drawable-xhdpi/btn_check_anim_00004_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00005_qntm_alpha.png Binary files differdeleted file mode 100644 index 58b3267..0000000 --- a/core/res/res/drawable-xhdpi/btn_check_anim_00005_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00006_qntm_alpha.png Binary files differdeleted file mode 100644 index 0659e72..0000000 --- a/core/res/res/drawable-xhdpi/btn_check_anim_00006_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00007_qntm_alpha.png Binary files differdeleted file mode 100644 index b4227d1..0000000 --- a/core/res/res/drawable-xhdpi/btn_check_anim_00007_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00008_qntm_alpha.png Binary files differdeleted file mode 100644 index 714ef00..0000000 --- a/core/res/res/drawable-xhdpi/btn_check_anim_00008_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00009_qntm_alpha.png Binary files differdeleted file mode 100644 index 139595b..0000000 --- a/core/res/res/drawable-xhdpi/btn_check_anim_00009_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00010_qntm_alpha.png Binary files differdeleted file mode 100644 index 4491107..0000000 --- a/core/res/res/drawable-xhdpi/btn_check_anim_00010_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00011_qntm_alpha.png Binary files differdeleted file mode 100644 index 20eb752..0000000 --- a/core/res/res/drawable-xhdpi/btn_check_anim_00011_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00012_qntm_alpha.png Binary files differdeleted file mode 100644 index 532c9f2..0000000 --- a/core/res/res/drawable-xhdpi/btn_check_anim_00012_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00013_qntm_alpha.png Binary files differdeleted file mode 100644 index 0d78a32..0000000 --- a/core/res/res/drawable-xhdpi/btn_check_anim_00013_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00014_qntm_alpha.png Binary files differdeleted file mode 100644 index af29678..0000000 --- a/core/res/res/drawable-xhdpi/btn_check_anim_00014_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00015_qntm_alpha.png Binary files differdeleted file mode 100644 index 23eb9e3..0000000 --- a/core/res/res/drawable-xhdpi/btn_check_anim_00015_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_check_off_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_off_qntm_alpha.png Binary files differdeleted file mode 100644 index 5d820ae..0000000 --- a/core/res/res/drawable-xhdpi/btn_check_off_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_check_on_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_on_qntm_alpha.png Binary files differdeleted file mode 100644 index 019c92e..0000000 --- a/core/res/res/drawable-xhdpi/btn_check_on_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_000.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_000.png Binary files differnew file mode 100644 index 0000000..2347643 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_000.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_001.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_001.png Binary files differnew file mode 100644 index 0000000..70aaa01 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_001.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_002.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_002.png Binary files differnew file mode 100644 index 0000000..01e498a --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_002.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_003.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_003.png Binary files differnew file mode 100644 index 0000000..71d1cf7 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_003.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_004.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_004.png Binary files differnew file mode 100644 index 0000000..d1e7b1d --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_004.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_005.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_005.png Binary files differnew file mode 100644 index 0000000..7db7d06 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_005.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_006.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_006.png Binary files differnew file mode 100644 index 0000000..dadb62e --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_006.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_007.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_007.png Binary files differnew file mode 100644 index 0000000..f87f744 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_007.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_008.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_008.png Binary files differnew file mode 100644 index 0000000..be99d87 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_008.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_009.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_009.png Binary files differnew file mode 100644 index 0000000..f83bc05 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_009.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_010.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_010.png Binary files differnew file mode 100644 index 0000000..870071d --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_010.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_011.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_011.png Binary files differnew file mode 100644 index 0000000..3a18414 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_011.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_012.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_012.png Binary files differnew file mode 100644 index 0000000..f3d1187 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_012.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_013.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_013.png Binary files differnew file mode 100644 index 0000000..4078cca --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_013.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_014.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_014.png Binary files differnew file mode 100644 index 0000000..d4849b5 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_014.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_015.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_015.png Binary files differnew file mode 100644 index 0000000..6e2af72 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_015.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_000.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_000.png Binary files differnew file mode 100644 index 0000000..9244174 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_000.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_001.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_001.png Binary files differnew file mode 100644 index 0000000..8c7fe95 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_001.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_002.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_002.png Binary files differnew file mode 100644 index 0000000..71eb1d0 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_002.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_003.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_003.png Binary files differnew file mode 100644 index 0000000..613f38a --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_003.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_004.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_004.png Binary files differnew file mode 100644 index 0000000..2d20ccc --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_004.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_005.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_005.png Binary files differnew file mode 100644 index 0000000..407f78d --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_005.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_006.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_006.png Binary files differnew file mode 100644 index 0000000..1bf24b0 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_006.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_007.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_007.png Binary files differnew file mode 100644 index 0000000..a450bd0 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_007.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_008.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_008.png Binary files differnew file mode 100644 index 0000000..63ba593 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_008.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_009.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_009.png Binary files differnew file mode 100644 index 0000000..6d05e5a --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_009.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_010.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_010.png Binary files differnew file mode 100644 index 0000000..1c8cd8f --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_010.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_011.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_011.png Binary files differnew file mode 100644 index 0000000..b8bc564 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_011.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_012.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_012.png Binary files differnew file mode 100644 index 0000000..3d80128 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_012.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_013.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_013.png Binary files differnew file mode 100644 index 0000000..c21dfba --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_013.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_014.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_014.png Binary files differnew file mode 100644 index 0000000..2dfe90d --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_014.png diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_015.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_015.png Binary files differnew file mode 100644 index 0000000..5f40d73 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_015.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00000_qntm_alpha.png Binary files differdeleted file mode 100644 index cd11e14..0000000 --- a/core/res/res/drawable-xhdpi/btn_radio_anim_00000_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00001_qntm_alpha.png Binary files differdeleted file mode 100644 index b10db83..0000000 --- a/core/res/res/drawable-xhdpi/btn_radio_anim_00001_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00002_qntm_alpha.png Binary files differdeleted file mode 100644 index efeb6fb..0000000 --- a/core/res/res/drawable-xhdpi/btn_radio_anim_00002_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00003_qntm_alpha.png Binary files differdeleted file mode 100644 index 83080af..0000000 --- a/core/res/res/drawable-xhdpi/btn_radio_anim_00003_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00004_qntm_alpha.png Binary files differdeleted file mode 100644 index b9cc322..0000000 --- a/core/res/res/drawable-xhdpi/btn_radio_anim_00004_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00005_qntm_alpha.png Binary files differdeleted file mode 100644 index 3b5f9c4..0000000 --- a/core/res/res/drawable-xhdpi/btn_radio_anim_00005_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00006_qntm_alpha.png Binary files differdeleted file mode 100644 index 58c93db..0000000 --- a/core/res/res/drawable-xhdpi/btn_radio_anim_00006_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00007_qntm_alpha.png Binary files differdeleted file mode 100644 index 0f1d010..0000000 --- a/core/res/res/drawable-xhdpi/btn_radio_anim_00007_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00008_qntm_alpha.png Binary files differdeleted file mode 100644 index 05a7a0f..0000000 --- a/core/res/res/drawable-xhdpi/btn_radio_anim_00008_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00009_qntm_alpha.png Binary files differdeleted file mode 100644 index 9345035..0000000 --- a/core/res/res/drawable-xhdpi/btn_radio_anim_00009_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00010_qntm_alpha.png Binary files differdeleted file mode 100644 index 5f149b7..0000000 --- a/core/res/res/drawable-xhdpi/btn_radio_anim_00010_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00011_qntm_alpha.png Binary files differdeleted file mode 100644 index 191f369..0000000 --- a/core/res/res/drawable-xhdpi/btn_radio_anim_00011_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00012_qntm_alpha.png Binary files differdeleted file mode 100644 index 44e08e6..0000000 --- a/core/res/res/drawable-xhdpi/btn_radio_anim_00012_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00013_qntm_alpha.png Binary files differdeleted file mode 100644 index 5a9dfa0..0000000 --- a/core/res/res/drawable-xhdpi/btn_radio_anim_00013_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00014_qntm_alpha.png Binary files differdeleted file mode 100644 index ee921c6..0000000 --- a/core/res/res/drawable-xhdpi/btn_radio_anim_00014_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00015_qntm_alpha.png Binary files differdeleted file mode 100644 index 567bb0c..0000000 --- a/core/res/res/drawable-xhdpi/btn_radio_anim_00015_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_off_pressed_qntm_alpha.png Binary files differdeleted file mode 100644 index 2fd964e..0000000 --- a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_radio_off_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_off_qntm_alpha.png Binary files differdeleted file mode 100644 index 8873cd6..0000000 --- a/core/res/res/drawable-xhdpi/btn_radio_off_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_000.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_000.png Binary files differnew file mode 100644 index 0000000..b54c6ff --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_000.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_001.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_001.png Binary files differnew file mode 100644 index 0000000..fff7056 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_001.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_002.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_002.png Binary files differnew file mode 100644 index 0000000..026462d --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_002.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_003.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_003.png Binary files differnew file mode 100644 index 0000000..26cc8de --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_003.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_004.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_004.png Binary files differnew file mode 100644 index 0000000..c055fff --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_004.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_005.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_005.png Binary files differnew file mode 100644 index 0000000..a22e780 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_005.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_006.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_006.png Binary files differnew file mode 100644 index 0000000..357374c --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_006.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_007.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_007.png Binary files differnew file mode 100644 index 0000000..71d4667 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_007.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_008.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_008.png Binary files differnew file mode 100644 index 0000000..2ed175e --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_008.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_009.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_009.png Binary files differnew file mode 100644 index 0000000..e0f7d8e --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_009.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_010.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_010.png Binary files differnew file mode 100644 index 0000000..62b0578 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_010.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_011.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_011.png Binary files differnew file mode 100644 index 0000000..4d6ef4a --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_011.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_012.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_012.png Binary files differnew file mode 100644 index 0000000..37cee2d --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_012.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_013.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_013.png Binary files differnew file mode 100644 index 0000000..a8bc25f --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_013.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_014.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_014.png Binary files differnew file mode 100644 index 0000000..cf68d93 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_014.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_015.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_015.png Binary files differnew file mode 100644 index 0000000..96834bc --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_015.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_000.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_000.png Binary files differnew file mode 100644 index 0000000..d068dbe --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_000.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_001.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_001.png Binary files differnew file mode 100644 index 0000000..4aabb1e --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_001.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_002.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_002.png Binary files differnew file mode 100644 index 0000000..bbac8e4 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_002.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_003.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_003.png Binary files differnew file mode 100644 index 0000000..2fc7459 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_003.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_004.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_004.png Binary files differnew file mode 100644 index 0000000..83c6d0e --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_004.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_005.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_005.png Binary files differnew file mode 100644 index 0000000..45c08d7 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_005.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_006.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_006.png Binary files differnew file mode 100644 index 0000000..05b7dfb --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_006.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_007.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_007.png Binary files differnew file mode 100644 index 0000000..baf9964 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_007.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_008.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_008.png Binary files differnew file mode 100644 index 0000000..d6e0369 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_008.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_009.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_009.png Binary files differnew file mode 100644 index 0000000..3f35270 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_009.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_010.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_010.png Binary files differnew file mode 100644 index 0000000..a5b34dc --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_010.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_011.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_011.png Binary files differnew file mode 100644 index 0000000..361967b --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_011.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_012.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_012.png Binary files differnew file mode 100644 index 0000000..c478bb7 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_012.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_013.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_013.png Binary files differnew file mode 100644 index 0000000..075fa0c --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_013.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_014.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_014.png Binary files differnew file mode 100644 index 0000000..d9e364b --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_014.png diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_015.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_015.png Binary files differnew file mode 100644 index 0000000..9924496 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_015.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_000.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_000.png Binary files differnew file mode 100644 index 0000000..2494fd4 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_000.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_001.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_001.png Binary files differnew file mode 100644 index 0000000..7bd99fe --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_001.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_002.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_002.png Binary files differnew file mode 100644 index 0000000..2ef623b --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_002.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_003.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_003.png Binary files differnew file mode 100644 index 0000000..19db3e0 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_003.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_004.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_004.png Binary files differnew file mode 100644 index 0000000..984c3c5 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_004.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_005.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_005.png Binary files differnew file mode 100644 index 0000000..6454190 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_005.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_006.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_006.png Binary files differnew file mode 100644 index 0000000..cee9393 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_006.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_007.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_007.png Binary files differnew file mode 100644 index 0000000..cee9393 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_007.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_008.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_008.png Binary files differnew file mode 100644 index 0000000..437ffdd --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_008.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_009.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_009.png Binary files differnew file mode 100644 index 0000000..d2e14ad --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_009.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_010.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_010.png Binary files differnew file mode 100644 index 0000000..4e2f5bc --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_010.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_011.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_011.png Binary files differnew file mode 100644 index 0000000..4e2f5bc --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_011.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_012.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_012.png Binary files differnew file mode 100644 index 0000000..4e2f5bc --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_012.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_013.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_013.png Binary files differnew file mode 100644 index 0000000..4e2f5bc --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_013.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_014.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_014.png Binary files differnew file mode 100644 index 0000000..4e2f5bc --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_014.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_000.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_000.png Binary files differnew file mode 100644 index 0000000..f1bcfa3 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_000.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_001.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_001.png Binary files differnew file mode 100644 index 0000000..ede2fec --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_001.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_002.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_002.png Binary files differnew file mode 100644 index 0000000..94ce017 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_002.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_003.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_003.png Binary files differnew file mode 100644 index 0000000..647cfe3 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_003.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_004.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_004.png Binary files differnew file mode 100644 index 0000000..b3bf923 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_004.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_005.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_005.png Binary files differnew file mode 100644 index 0000000..ae95b2b --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_005.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_006.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_006.png Binary files differnew file mode 100644 index 0000000..b8e4bd6 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_006.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_007.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_007.png Binary files differnew file mode 100644 index 0000000..ec6d6d7 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_007.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_008.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_008.png Binary files differnew file mode 100644 index 0000000..c0e493f --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_008.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_009.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_009.png Binary files differnew file mode 100644 index 0000000..2494fd4 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_009.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_010.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_010.png Binary files differnew file mode 100644 index 0000000..2494fd4 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_010.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_011.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_011.png Binary files differnew file mode 100644 index 0000000..2494fd4 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_011.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_012.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_012.png Binary files differnew file mode 100644 index 0000000..2494fd4 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_012.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_013.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_013.png Binary files differnew file mode 100644 index 0000000..2494fd4 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_013.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_014.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_014.png Binary files differnew file mode 100644 index 0000000..2494fd4 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_014.png diff --git a/core/res/res/drawable-xhdpi/btn_toggle_indicator_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/btn_toggle_indicator_qntm_alpha.9.png Binary files differnew file mode 100644 index 0000000..dff391f --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_toggle_indicator_qntm_alpha.9.png diff --git a/core/res/res/drawable-xhdpi/btn_toggle_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/btn_toggle_qntm_alpha.9.png Binary files differnew file mode 100644 index 0000000..b135338 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_toggle_qntm_alpha.9.png diff --git a/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_000.png b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_000.png Binary files differnew file mode 100644 index 0000000..ea09a31 --- /dev/null +++ b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_000.png diff --git a/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_001.png b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_001.png Binary files differnew file mode 100644 index 0000000..f9a4391 --- /dev/null +++ b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_001.png diff --git a/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_002.png b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_002.png Binary files differnew file mode 100644 index 0000000..d9606e1 --- /dev/null +++ b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_002.png diff --git a/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_003.png b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_003.png Binary files differnew file mode 100644 index 0000000..df2d9d0 --- /dev/null +++ b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_003.png diff --git a/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_004.png b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_004.png Binary files differnew file mode 100644 index 0000000..625a322 --- /dev/null +++ b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_004.png diff --git a/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_005.png b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_005.png Binary files differnew file mode 100644 index 0000000..79e8dde --- /dev/null +++ b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_005.png diff --git a/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_000.png b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_000.png Binary files differnew file mode 100644 index 0000000..e99c266 --- /dev/null +++ b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_000.png diff --git a/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_001.png b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_001.png Binary files differnew file mode 100644 index 0000000..f0329a4 --- /dev/null +++ b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_001.png diff --git a/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_002.png b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_002.png Binary files differnew file mode 100644 index 0000000..42c40b7 --- /dev/null +++ b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_002.png diff --git a/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_003.png b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_003.png Binary files differnew file mode 100644 index 0000000..807491f --- /dev/null +++ b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_003.png diff --git a/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_004.png b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_004.png Binary files differnew file mode 100644 index 0000000..dfec9cc --- /dev/null +++ b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_004.png diff --git a/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_005.png b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_005.png Binary files differnew file mode 100644 index 0000000..0ed59ea --- /dev/null +++ b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_005.png diff --git a/core/res/res/drawable-xhdpi/switch_off_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/switch_off_qntm_alpha.9.png Binary files differdeleted file mode 100644 index a7a972c..0000000 --- a/core/res/res/drawable-xhdpi/switch_off_qntm_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/switch_on_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/switch_on_qntm_alpha.9.png Binary files differdeleted file mode 100644 index dd8910b..0000000 --- a/core/res/res/drawable-xhdpi/switch_on_qntm_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/switch_track_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/switch_track_qntm_alpha.9.png Binary files differindex 4970f56..d6a0ab2 100644 --- a/core/res/res/drawable-xhdpi/switch_track_qntm_alpha.9.png +++ b/core/res/res/drawable-xhdpi/switch_track_qntm_alpha.9.png diff --git a/core/res/res/drawable-xhdpi/text_select_handle_left_qntm_alpha.png b/core/res/res/drawable-xhdpi/text_select_handle_left_qntm_alpha.png Binary files differindex 38b8e8b..a01ac10 100644 --- a/core/res/res/drawable-xhdpi/text_select_handle_left_qntm_alpha.png +++ b/core/res/res/drawable-xhdpi/text_select_handle_left_qntm_alpha.png diff --git a/core/res/res/drawable-xhdpi/text_select_handle_right_qntm_alpha.png b/core/res/res/drawable-xhdpi/text_select_handle_right_qntm_alpha.png Binary files differindex d6002a7..d3602d9 100644 --- a/core/res/res/drawable-xhdpi/text_select_handle_right_qntm_alpha.png +++ b/core/res/res/drawable-xhdpi/text_select_handle_right_qntm_alpha.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00000_qntm_alpha.png Binary files differdeleted file mode 100644 index 1881f54..0000000 --- a/core/res/res/drawable-xxhdpi/btn_check_anim_00000_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00001_qntm_alpha.png Binary files differdeleted file mode 100644 index 6f8ec2d..0000000 --- a/core/res/res/drawable-xxhdpi/btn_check_anim_00001_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00002_qntm_alpha.png Binary files differdeleted file mode 100644 index c954ed9..0000000 --- a/core/res/res/drawable-xxhdpi/btn_check_anim_00002_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00003_qntm_alpha.png Binary files differdeleted file mode 100644 index 9d1a47e..0000000 --- a/core/res/res/drawable-xxhdpi/btn_check_anim_00003_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00004_qntm_alpha.png Binary files differdeleted file mode 100644 index ce63631..0000000 --- a/core/res/res/drawable-xxhdpi/btn_check_anim_00004_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00005_qntm_alpha.png Binary files differdeleted file mode 100644 index 430c134..0000000 --- a/core/res/res/drawable-xxhdpi/btn_check_anim_00005_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00006_qntm_alpha.png Binary files differdeleted file mode 100644 index cdebf83..0000000 --- a/core/res/res/drawable-xxhdpi/btn_check_anim_00006_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00007_qntm_alpha.png Binary files differdeleted file mode 100644 index 40ceadb..0000000 --- a/core/res/res/drawable-xxhdpi/btn_check_anim_00007_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00008_qntm_alpha.png Binary files differdeleted file mode 100644 index fb13eb2..0000000 --- a/core/res/res/drawable-xxhdpi/btn_check_anim_00008_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00009_qntm_alpha.png Binary files differdeleted file mode 100644 index d716fba..0000000 --- a/core/res/res/drawable-xxhdpi/btn_check_anim_00009_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00010_qntm_alpha.png Binary files differdeleted file mode 100644 index b8be041..0000000 --- a/core/res/res/drawable-xxhdpi/btn_check_anim_00010_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00011_qntm_alpha.png Binary files differdeleted file mode 100644 index bad0c3c..0000000 --- a/core/res/res/drawable-xxhdpi/btn_check_anim_00011_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00012_qntm_alpha.png Binary files differdeleted file mode 100644 index a6368fb..0000000 --- a/core/res/res/drawable-xxhdpi/btn_check_anim_00012_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00013_qntm_alpha.png Binary files differdeleted file mode 100644 index 234e5d1..0000000 --- a/core/res/res/drawable-xxhdpi/btn_check_anim_00013_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00014_qntm_alpha.png Binary files differdeleted file mode 100644 index 3e7796d..0000000 --- a/core/res/res/drawable-xxhdpi/btn_check_anim_00014_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00015_qntm_alpha.png Binary files differdeleted file mode 100644 index 0673999..0000000 --- a/core/res/res/drawable-xxhdpi/btn_check_anim_00015_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_off_qntm_alpha.png Binary files differdeleted file mode 100644 index 2a17861..0000000 --- a/core/res/res/drawable-xxhdpi/btn_check_off_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_on_qntm_alpha.png Binary files differdeleted file mode 100644 index 61067ac..0000000 --- a/core/res/res/drawable-xxhdpi/btn_check_on_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_000.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_000.png Binary files differnew file mode 100644 index 0000000..b754381 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_000.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_001.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_001.png Binary files differnew file mode 100644 index 0000000..517d7a7 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_001.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_002.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_002.png Binary files differnew file mode 100644 index 0000000..2c1d5b6 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_002.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_003.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_003.png Binary files differnew file mode 100644 index 0000000..0c6ff7e --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_003.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_004.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_004.png Binary files differnew file mode 100644 index 0000000..0796601 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_004.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_005.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_005.png Binary files differnew file mode 100644 index 0000000..9b4e0f8 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_005.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_006.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_006.png Binary files differnew file mode 100644 index 0000000..25767eb --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_006.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_007.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_007.png Binary files differnew file mode 100644 index 0000000..cd0951f --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_007.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_008.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_008.png Binary files differnew file mode 100644 index 0000000..9ae8165 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_008.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_009.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_009.png Binary files differnew file mode 100644 index 0000000..efd9bc6 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_009.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_010.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_010.png Binary files differnew file mode 100644 index 0000000..fccbc9d --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_010.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_011.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_011.png Binary files differnew file mode 100644 index 0000000..dddafca --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_011.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_012.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_012.png Binary files differnew file mode 100644 index 0000000..7e37433 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_012.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_013.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_013.png Binary files differnew file mode 100644 index 0000000..9bc22de --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_013.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_014.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_014.png Binary files differnew file mode 100644 index 0000000..507ed10 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_014.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_015.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_015.png Binary files differnew file mode 100644 index 0000000..6a21c7f --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_015.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_000.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_000.png Binary files differnew file mode 100644 index 0000000..0d544d9 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_000.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_001.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_001.png Binary files differnew file mode 100644 index 0000000..39da0ac --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_001.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_002.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_002.png Binary files differnew file mode 100644 index 0000000..d5ada12 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_002.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_003.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_003.png Binary files differnew file mode 100644 index 0000000..d4e096c --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_003.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_004.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_004.png Binary files differnew file mode 100644 index 0000000..468a9b4 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_004.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_005.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_005.png Binary files differnew file mode 100644 index 0000000..ea3cd2e --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_005.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_006.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_006.png Binary files differnew file mode 100644 index 0000000..0652cb0 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_006.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_007.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_007.png Binary files differnew file mode 100644 index 0000000..768d2b0 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_007.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_008.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_008.png Binary files differnew file mode 100644 index 0000000..1d06a90 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_008.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_009.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_009.png Binary files differnew file mode 100644 index 0000000..8a70a80 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_009.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_010.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_010.png Binary files differnew file mode 100644 index 0000000..bf9ec7f --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_010.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_011.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_011.png Binary files differnew file mode 100644 index 0000000..cff07b9 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_011.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_012.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_012.png Binary files differnew file mode 100644 index 0000000..40f997e --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_012.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_013.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_013.png Binary files differnew file mode 100644 index 0000000..6ba84ec --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_013.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_014.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_014.png Binary files differnew file mode 100644 index 0000000..766610e --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_014.png diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_015.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_015.png Binary files differnew file mode 100644 index 0000000..810a029 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_015.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_qntm_alpha.png Binary files differdeleted file mode 100644 index fdbbbce..0000000 --- a/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_off_qntm_alpha.png Binary files differdeleted file mode 100644 index 0ec2ee6..0000000 --- a/core/res/res/drawable-xxhdpi/btn_radio_off_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_qntm_alpha.png Binary files differdeleted file mode 100644 index b46ee1c..0000000 --- a/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_on_qntm_alpha.png Binary files differdeleted file mode 100644 index 8737156..0000000 --- a/core/res/res/drawable-xxhdpi/btn_radio_on_qntm_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_000.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_000.png Binary files differnew file mode 100644 index 0000000..cbc3833 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_000.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_001.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_001.png Binary files differnew file mode 100644 index 0000000..4243895 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_001.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_002.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_002.png Binary files differnew file mode 100644 index 0000000..b522d37 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_002.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_003.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_003.png Binary files differnew file mode 100644 index 0000000..647b965 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_003.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_004.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_004.png Binary files differnew file mode 100644 index 0000000..a317497 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_004.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_005.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_005.png Binary files differnew file mode 100644 index 0000000..0e4b25f --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_005.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_006.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_006.png Binary files differnew file mode 100644 index 0000000..6e279d9 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_006.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_007.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_007.png Binary files differnew file mode 100644 index 0000000..f0840cc --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_007.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_008.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_008.png Binary files differnew file mode 100644 index 0000000..140e9e8 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_008.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_009.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_009.png Binary files differnew file mode 100644 index 0000000..5cf8ec5 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_009.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_010.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_010.png Binary files differnew file mode 100644 index 0000000..f9624d8 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_010.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_011.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_011.png Binary files differnew file mode 100644 index 0000000..899df8c --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_011.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_012.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_012.png Binary files differnew file mode 100644 index 0000000..6543e1c --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_012.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_013.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_013.png Binary files differnew file mode 100644 index 0000000..cd758dd --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_013.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_014.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_014.png Binary files differnew file mode 100644 index 0000000..72d950c --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_014.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_015.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_015.png Binary files differnew file mode 100644 index 0000000..07bdbc9 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_015.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_000.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_000.png Binary files differnew file mode 100644 index 0000000..c9af24b --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_000.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_001.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_001.png Binary files differnew file mode 100644 index 0000000..01de3f5 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_001.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_002.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_002.png Binary files differnew file mode 100644 index 0000000..f428bc5 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_002.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_003.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_003.png Binary files differnew file mode 100644 index 0000000..ab5c008 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_003.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_004.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_004.png Binary files differnew file mode 100644 index 0000000..5b157cf --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_004.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_005.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_005.png Binary files differnew file mode 100644 index 0000000..1210be2 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_005.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_006.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_006.png Binary files differnew file mode 100644 index 0000000..e6b4140 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_006.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_007.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_007.png Binary files differnew file mode 100644 index 0000000..b678e08 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_007.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_008.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_008.png Binary files differnew file mode 100644 index 0000000..6ca2a69 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_008.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_009.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_009.png Binary files differnew file mode 100644 index 0000000..7de608e --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_009.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_010.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_010.png Binary files differnew file mode 100644 index 0000000..b2bbcce --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_010.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_011.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_011.png Binary files differnew file mode 100644 index 0000000..6950db3 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_011.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_012.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_012.png Binary files differnew file mode 100644 index 0000000..c790756 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_012.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_013.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_013.png Binary files differnew file mode 100644 index 0000000..ed5d888 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_013.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_014.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_014.png Binary files differnew file mode 100644 index 0000000..81a4a63 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_014.png diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_015.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_015.png Binary files differnew file mode 100644 index 0000000..db1d93a --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_015.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_000.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_000.png Binary files differnew file mode 100644 index 0000000..198ac07 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_000.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_001.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_001.png Binary files differnew file mode 100644 index 0000000..eff3dd0 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_001.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_002.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_002.png Binary files differnew file mode 100644 index 0000000..000a23a --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_002.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_003.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_003.png Binary files differnew file mode 100644 index 0000000..394d661 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_003.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_004.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_004.png Binary files differnew file mode 100644 index 0000000..4e7311d --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_004.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_005.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_005.png Binary files differnew file mode 100644 index 0000000..d9dcf91 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_005.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_006.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_006.png Binary files differnew file mode 100644 index 0000000..674142e --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_006.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_007.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_007.png Binary files differnew file mode 100644 index 0000000..674142e --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_007.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_008.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_008.png Binary files differnew file mode 100644 index 0000000..9d4026a --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_008.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_009.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_009.png Binary files differnew file mode 100644 index 0000000..bb4b426 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_009.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_010.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_010.png Binary files differnew file mode 100644 index 0000000..a37076d --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_010.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_011.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_011.png Binary files differnew file mode 100644 index 0000000..a37076d --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_011.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_012.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_012.png Binary files differnew file mode 100644 index 0000000..a37076d --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_012.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_013.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_013.png Binary files differnew file mode 100644 index 0000000..a37076d --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_013.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_014.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_014.png Binary files differnew file mode 100644 index 0000000..a37076d --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_014.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_000.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_000.png Binary files differnew file mode 100644 index 0000000..22e9951 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_000.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_001.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_001.png Binary files differnew file mode 100644 index 0000000..14e6b39 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_001.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_002.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_002.png Binary files differnew file mode 100644 index 0000000..86b2c01 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_002.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_003.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_003.png Binary files differnew file mode 100644 index 0000000..1c565df --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_003.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_004.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_004.png Binary files differnew file mode 100644 index 0000000..b825449 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_004.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_005.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_005.png Binary files differnew file mode 100644 index 0000000..170c234 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_005.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_006.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_006.png Binary files differnew file mode 100644 index 0000000..5477007 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_006.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_007.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_007.png Binary files differnew file mode 100644 index 0000000..eff3dd0 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_007.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_008.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_008.png Binary files differnew file mode 100644 index 0000000..e3fd96a --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_008.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_009.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_009.png Binary files differnew file mode 100644 index 0000000..198ac07 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_009.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_010.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_010.png Binary files differnew file mode 100644 index 0000000..198ac07 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_010.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_011.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_011.png Binary files differnew file mode 100644 index 0000000..198ac07 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_011.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_012.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_012.png Binary files differnew file mode 100644 index 0000000..198ac07 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_012.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_013.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_013.png Binary files differnew file mode 100644 index 0000000..198ac07 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_013.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_014.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_014.png Binary files differnew file mode 100644 index 0000000..198ac07 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_014.png diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_indicator_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_indicator_qntm_alpha.9.png Binary files differnew file mode 100644 index 0000000..0d6a39a --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_toggle_indicator_qntm_alpha.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_qntm_alpha.9.png Binary files differnew file mode 100644 index 0000000..f235aed --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_toggle_qntm_alpha.9.png diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_000.png b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_000.png Binary files differnew file mode 100644 index 0000000..46aa533 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_000.png diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_001.png b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_001.png Binary files differnew file mode 100644 index 0000000..a749469 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_001.png diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_002.png b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_002.png Binary files differnew file mode 100644 index 0000000..ef43f00 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_002.png diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_003.png b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_003.png Binary files differnew file mode 100644 index 0000000..eebddc3 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_003.png diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_004.png b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_004.png Binary files differnew file mode 100644 index 0000000..44b654d --- /dev/null +++ b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_004.png diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_005.png b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_005.png Binary files differnew file mode 100644 index 0000000..6e768c1 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_005.png diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_000.png b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_000.png Binary files differnew file mode 100644 index 0000000..2ac6dae --- /dev/null +++ b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_000.png diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_001.png b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_001.png Binary files differnew file mode 100644 index 0000000..91c49ce --- /dev/null +++ b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_001.png diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_002.png b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_002.png Binary files differnew file mode 100644 index 0000000..4b4bd1f --- /dev/null +++ b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_002.png diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_003.png b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_003.png Binary files differnew file mode 100644 index 0000000..637e596 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_003.png diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_004.png b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_004.png Binary files differnew file mode 100644 index 0000000..42d4d2a --- /dev/null +++ b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_004.png diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_005.png b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_005.png Binary files differnew file mode 100644 index 0000000..995d1b2 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_005.png diff --git a/core/res/res/drawable-xxhdpi/switch_off_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/switch_off_qntm_alpha.9.png Binary files differdeleted file mode 100644 index 8d79a13..0000000 --- a/core/res/res/drawable-xxhdpi/switch_off_qntm_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/switch_on_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/switch_on_qntm_alpha.9.png Binary files differdeleted file mode 100644 index e0e4ef9..0000000 --- a/core/res/res/drawable-xxhdpi/switch_on_qntm_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/switch_track_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/switch_track_qntm_alpha.9.png Binary files differindex 74a259b..a8067cb 100644 --- a/core/res/res/drawable-xxhdpi/switch_track_qntm_alpha.9.png +++ b/core/res/res/drawable-xxhdpi/switch_track_qntm_alpha.9.png diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_left_qntm_alpha.png b/core/res/res/drawable-xxhdpi/text_select_handle_left_qntm_alpha.png Binary files differindex 93469a2..75085ce 100644 --- a/core/res/res/drawable-xxhdpi/text_select_handle_left_qntm_alpha.png +++ b/core/res/res/drawable-xxhdpi/text_select_handle_left_qntm_alpha.png diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_right_qntm_alpha.png b/core/res/res/drawable-xxhdpi/text_select_handle_right_qntm_alpha.png Binary files differindex b3493e7..e2eb5be 100644 --- a/core/res/res/drawable-xxhdpi/text_select_handle_right_qntm_alpha.png +++ b/core/res/res/drawable-xxhdpi/text_select_handle_right_qntm_alpha.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_000.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_000.png Binary files differnew file mode 100644 index 0000000..f0ff1a7 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_000.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_001.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_001.png Binary files differnew file mode 100644 index 0000000..b382df3 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_001.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_002.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_002.png Binary files differnew file mode 100644 index 0000000..8cb4ce2 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_002.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_003.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_003.png Binary files differnew file mode 100644 index 0000000..4db2b01 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_003.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_004.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_004.png Binary files differnew file mode 100644 index 0000000..8c4709b --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_004.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_005.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_005.png Binary files differnew file mode 100644 index 0000000..1ad960a --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_005.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_006.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_006.png Binary files differnew file mode 100644 index 0000000..e47cc20 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_006.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_007.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_007.png Binary files differnew file mode 100644 index 0000000..c4d0d51 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_007.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_008.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_008.png Binary files differnew file mode 100644 index 0000000..915d56a --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_008.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_009.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_009.png Binary files differnew file mode 100644 index 0000000..85795cb --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_009.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_010.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_010.png Binary files differnew file mode 100644 index 0000000..157fd91 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_010.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_011.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_011.png Binary files differnew file mode 100644 index 0000000..9d446de --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_011.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_012.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_012.png Binary files differnew file mode 100644 index 0000000..dfac1f0 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_012.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_013.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_013.png Binary files differnew file mode 100644 index 0000000..aed6c08 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_013.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_014.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_014.png Binary files differnew file mode 100644 index 0000000..1b8bd6b --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_014.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_015.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_015.png Binary files differnew file mode 100644 index 0000000..5dd0e5b --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_015.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_000.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_000.png Binary files differnew file mode 100644 index 0000000..5dd0e5b --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_000.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_001.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_001.png Binary files differnew file mode 100644 index 0000000..1a31ad9 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_001.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_002.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_002.png Binary files differnew file mode 100644 index 0000000..63c7f12 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_002.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_003.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_003.png Binary files differnew file mode 100644 index 0000000..847dd08 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_003.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_004.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_004.png Binary files differnew file mode 100644 index 0000000..b93f3cc --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_004.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_005.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_005.png Binary files differnew file mode 100644 index 0000000..1e3dea7 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_005.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_006.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_006.png Binary files differnew file mode 100644 index 0000000..5a85238 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_006.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_007.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_007.png Binary files differnew file mode 100644 index 0000000..35960ca --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_007.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_008.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_008.png Binary files differnew file mode 100644 index 0000000..6db5555 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_008.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_009.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_009.png Binary files differnew file mode 100644 index 0000000..a9c5851 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_009.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_010.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_010.png Binary files differnew file mode 100644 index 0000000..38465bd --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_010.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_011.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_011.png Binary files differnew file mode 100644 index 0000000..15942dc --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_011.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_012.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_012.png Binary files differnew file mode 100644 index 0000000..67d0d64 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_012.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_013.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_013.png Binary files differnew file mode 100644 index 0000000..69b5c1b --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_013.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_014.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_014.png Binary files differnew file mode 100644 index 0000000..0e5d331 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_014.png diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_015.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_015.png Binary files differnew file mode 100644 index 0000000..f0ff1a7 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_015.png diff --git a/core/res/res/drawable-xxxhdpi/btn_qntm_alpha.9.png b/core/res/res/drawable-xxxhdpi/btn_qntm_alpha.9.png Binary files differnew file mode 100644 index 0000000..01eeefe --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_qntm_alpha.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_000.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_000.png Binary files differnew file mode 100644 index 0000000..44028af --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_000.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_001.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_001.png Binary files differnew file mode 100644 index 0000000..ec13a86 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_001.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_002.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_002.png Binary files differnew file mode 100644 index 0000000..43754eb --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_002.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_003.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_003.png Binary files differnew file mode 100644 index 0000000..39d1d64 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_003.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_004.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_004.png Binary files differnew file mode 100644 index 0000000..f36f883 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_004.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_005.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_005.png Binary files differnew file mode 100644 index 0000000..7a4cc5c --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_005.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_006.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_006.png Binary files differnew file mode 100644 index 0000000..80a21ec --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_006.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_007.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_007.png Binary files differnew file mode 100644 index 0000000..2141104 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_007.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_008.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_008.png Binary files differnew file mode 100644 index 0000000..203bd51 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_008.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_009.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_009.png Binary files differnew file mode 100644 index 0000000..5df6fc5 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_009.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_010.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_010.png Binary files differnew file mode 100644 index 0000000..6d0fced --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_010.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_011.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_011.png Binary files differnew file mode 100644 index 0000000..8c0c372 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_011.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_012.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_012.png Binary files differnew file mode 100644 index 0000000..4fa6f53 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_012.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_013.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_013.png Binary files differnew file mode 100644 index 0000000..d3dbf7d --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_013.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_014.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_014.png Binary files differnew file mode 100644 index 0000000..4ccf8de --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_014.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_015.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_015.png Binary files differnew file mode 100644 index 0000000..adef871 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_015.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_000.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_000.png Binary files differnew file mode 100644 index 0000000..adef871 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_000.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_001.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_001.png Binary files differnew file mode 100644 index 0000000..9fc3556 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_001.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_002.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_002.png Binary files differnew file mode 100644 index 0000000..7f00609 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_002.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_003.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_003.png Binary files differnew file mode 100644 index 0000000..e4aa58d --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_003.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_004.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_004.png Binary files differnew file mode 100644 index 0000000..fe4e4b7 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_004.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_005.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_005.png Binary files differnew file mode 100644 index 0000000..86666ca --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_005.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_006.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_006.png Binary files differnew file mode 100644 index 0000000..608faaf --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_006.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_007.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_007.png Binary files differnew file mode 100644 index 0000000..ec95422 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_007.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_008.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_008.png Binary files differnew file mode 100644 index 0000000..76e2754 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_008.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_009.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_009.png Binary files differnew file mode 100644 index 0000000..3853eac --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_009.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_010.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_010.png Binary files differnew file mode 100644 index 0000000..621aff1 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_010.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_011.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_011.png Binary files differnew file mode 100644 index 0000000..d24be2a --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_011.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_012.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_012.png Binary files differnew file mode 100644 index 0000000..df33892 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_012.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_013.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_013.png Binary files differnew file mode 100644 index 0000000..ff4b818 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_013.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_014.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_014.png Binary files differnew file mode 100644 index 0000000..d9793ae --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_014.png diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_015.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_015.png Binary files differnew file mode 100644 index 0000000..44028af --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_015.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_000.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_000.png Binary files differnew file mode 100644 index 0000000..8b202c6 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_000.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_001.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_001.png Binary files differnew file mode 100644 index 0000000..3b497f3 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_001.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_002.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_002.png Binary files differnew file mode 100644 index 0000000..532b6de --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_002.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_003.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_003.png Binary files differnew file mode 100644 index 0000000..403b2fe --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_003.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_004.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_004.png Binary files differnew file mode 100644 index 0000000..8c5086c --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_004.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_005.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_005.png Binary files differnew file mode 100644 index 0000000..d4870f8 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_005.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_006.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_006.png Binary files differnew file mode 100644 index 0000000..c05adf5 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_006.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_007.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_007.png Binary files differnew file mode 100644 index 0000000..99b2056 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_007.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_008.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_008.png Binary files differnew file mode 100644 index 0000000..d839358 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_008.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_009.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_009.png Binary files differnew file mode 100644 index 0000000..913f94d --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_009.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_010.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_010.png Binary files differnew file mode 100644 index 0000000..7f325b3 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_010.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_011.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_011.png Binary files differnew file mode 100644 index 0000000..149a9aa --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_011.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_012.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_012.png Binary files differnew file mode 100644 index 0000000..95c219e --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_012.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_013.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_013.png Binary files differnew file mode 100644 index 0000000..462a128 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_013.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_014.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_014.png Binary files differnew file mode 100644 index 0000000..5911d16 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_014.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_000.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_000.png Binary files differnew file mode 100644 index 0000000..e0c6d85 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_000.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_001.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_001.png Binary files differnew file mode 100644 index 0000000..5679943 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_001.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_002.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_002.png Binary files differnew file mode 100644 index 0000000..54b636d --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_002.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_003.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_003.png Binary files differnew file mode 100644 index 0000000..bf9fac0 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_003.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_004.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_004.png Binary files differnew file mode 100644 index 0000000..25d5319 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_004.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_005.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_005.png Binary files differnew file mode 100644 index 0000000..d2df595 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_005.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_006.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_006.png Binary files differnew file mode 100644 index 0000000..7700bde --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_006.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_007.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_007.png Binary files differnew file mode 100644 index 0000000..883f98b --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_007.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_008.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_008.png Binary files differnew file mode 100644 index 0000000..b3b2108 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_008.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_009.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_009.png Binary files differnew file mode 100644 index 0000000..3aad596 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_009.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_010.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_010.png Binary files differnew file mode 100644 index 0000000..2017e17 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_010.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_011.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_011.png Binary files differnew file mode 100644 index 0000000..1fc2700 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_011.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_012.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_012.png Binary files differnew file mode 100644 index 0000000..bb8b0f2 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_012.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_013.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_013.png Binary files differnew file mode 100644 index 0000000..66ab8f6 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_013.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_014.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_014.png Binary files differnew file mode 100644 index 0000000..e3424db --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_014.png diff --git a/core/res/res/drawable-xxxhdpi/btn_toggle_indicator_qntm_alpha.9.png b/core/res/res/drawable-xxxhdpi/btn_toggle_indicator_qntm_alpha.9.png Binary files differnew file mode 100755 index 0000000..c06740b --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_toggle_indicator_qntm_alpha.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_toggle_qntm_alpha.9.png b/core/res/res/drawable-xxxhdpi/btn_toggle_qntm_alpha.9.png Binary files differnew file mode 100755 index 0000000..7556167 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_toggle_qntm_alpha.9.png diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_000.png b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_000.png Binary files differnew file mode 100644 index 0000000..0c8f746 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_000.png diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_001.png b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_001.png Binary files differnew file mode 100644 index 0000000..5db9deb --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_001.png diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_002.png b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_002.png Binary files differnew file mode 100644 index 0000000..3aca6d3 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_002.png diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_003.png b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_003.png Binary files differnew file mode 100644 index 0000000..746c74f --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_003.png diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_004.png b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_004.png Binary files differnew file mode 100644 index 0000000..454a5b2 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_004.png diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_005.png b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_005.png Binary files differnew file mode 100644 index 0000000..80ad8cc --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_005.png diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_000.png b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_000.png Binary files differnew file mode 100644 index 0000000..cfd0db4 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_000.png diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_001.png b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_001.png Binary files differnew file mode 100644 index 0000000..845092f --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_001.png diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_002.png b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_002.png Binary files differnew file mode 100644 index 0000000..0042db4 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_002.png diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_003.png b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_003.png Binary files differnew file mode 100644 index 0000000..77b2901 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_003.png diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_004.png b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_004.png Binary files differnew file mode 100644 index 0000000..fb3c238 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_004.png diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_005.png b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_005.png Binary files differnew file mode 100644 index 0000000..0d28c45 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_005.png diff --git a/core/res/res/drawable-xxxhdpi/switch_track_qntm_alpha.9.png b/core/res/res/drawable-xxxhdpi/switch_track_qntm_alpha.9.png Binary files differnew file mode 100644 index 0000000..fb07f2a --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/switch_track_qntm_alpha.9.png diff --git a/core/res/res/drawable/btn_borderless_quantum.xml b/core/res/res/drawable/btn_borderless_quantum.xml index a8def44..2cd7ed6 100644 --- a/core/res/res/drawable/btn_borderless_quantum.xml +++ b/core/res/res/drawable/btn_borderless_quantum.xml @@ -16,21 +16,6 @@ <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:tint="?attr/colorControlHighlight"> - <item android:id="@id/mask"> - <inset - android:insetLeft="4dp" - android:insetTop="4dp" - android:insetBottom="4dp" - android:insetRight="4dp"> - <shape android:shape="rectangle"> - <solid android:color="@color/white" /> - <corners android:radius="2dp" /> - <padding - android:left="4dp" - android:top="4dp" - android:bottom="4dp" - android:right="4dp" /> - </shape> - </inset> - </item> + <item android:id="@id/mask" + android:drawable="@drawable/btn_qntm_alpha" /> </ripple> diff --git a/core/res/res/drawable/btn_check_quantum.xml b/core/res/res/drawable/btn_check_quantum.xml deleted file mode 100644 index 6ceba60..0000000 --- a/core/res/res/drawable/btn_check_quantum.xml +++ /dev/null @@ -1,34 +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_checked="true" android:state_pressed="true"> - <bitmap android:src="@drawable/btn_check_on_qntm_alpha" - android:tint="?attr/colorControlActivated" /> - </item> - <item android:state_checked="true"> - <bitmap android:src="@drawable/btn_check_on_qntm_alpha" - android:tint="?attr/colorControlActivated" /> - </item> - <item android:state_pressed="true"> - <bitmap android:src="@drawable/btn_check_off_qntm_alpha" - android:tint="?attr/colorControlActivated" /> - </item> - <item> - <bitmap android:src="@drawable/btn_check_off_qntm_alpha" - android:tint="?attr/colorControlNormal" /> - </item> -</selector> diff --git a/core/res/res/drawable/btn_check_quantum_anim.xml b/core/res/res/drawable/btn_check_quantum_anim.xml index 96715a4..b16875e 100644 --- a/core/res/res/drawable/btn_check_quantum_anim.xml +++ b/core/res/res/drawable/btn_check_quantum_anim.xml @@ -16,88 +16,118 @@ <animated-selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false" android:state_checked="true"> - <bitmap android:src="@drawable/btn_check_anim_00015_qntm_alpha" - android:tint="?attr/colorControlActivated" - android:alpha="?attr/disabledAlpha" /> + <bitmap android:src="@drawable/btn_check_to_on_qntm_015" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" /> </item> <item android:state_enabled="false"> - <bitmap android:src="@drawable/btn_check_anim_00000_qntm_alpha" - android:tint="?attr/colorControlNormal" - android:alpha="?attr/disabledAlpha" /> + <bitmap android:src="@drawable/btn_check_to_on_qntm_000" android:tint="?attr/colorControlNormal" android:alpha="?attr/disabledAlpha" /> </item> <item android:state_checked="true" android:id="@+id/on"> - <bitmap android:src="@drawable/btn_check_anim_00015_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <bitmap android:src="@drawable/btn_check_to_on_qntm_015" android:tint="?attr/colorControlActivated" /> </item> <item android:id="@+id/off"> - <bitmap android:src="@drawable/btn_check_anim_00000_qntm_alpha" - android:tint="?attr/colorControlNormal" /> + <bitmap android:src="@drawable/btn_check_to_on_qntm_000" android:tint="?attr/colorControlNormal" /> </item> - <transition android:fromId="@+id/off" android:toId="@+id/on" android:reversible="true"> + <transition android:fromId="@+id/off" android:toId="@+id/on"> <animation-list> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_check_anim_00000_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_on_qntm_000" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_check_anim_00001_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_on_qntm_001" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_check_anim_00002_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_on_qntm_002" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_check_anim_00003_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_on_qntm_003" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_check_anim_00004_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_on_qntm_004" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_check_anim_00005_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_on_qntm_005" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_check_anim_00006_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_on_qntm_006" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_check_anim_00007_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_on_qntm_007" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_check_anim_00008_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_on_qntm_008" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_check_anim_00009_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_on_qntm_009" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_check_anim_00010_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_on_qntm_010" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_check_anim_00011_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_on_qntm_011" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_check_anim_00012_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_on_qntm_012" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_check_anim_00013_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_on_qntm_013" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_check_anim_00014_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_on_qntm_014" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_check_anim_00015_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_on_qntm_015" android:tint="?attr/colorControlActivated" /> + </item> + </animation-list> + </transition> + <transition android:fromId="@+id/on" android:toId="@+id/off"> + <animation-list> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_off_qntm_000" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_off_qntm_001" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_off_qntm_002" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_off_qntm_003" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_off_qntm_004" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_off_qntm_005" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_off_qntm_006" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_off_qntm_007" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_off_qntm_008" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_off_qntm_009" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_off_qntm_010" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_off_qntm_011" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_off_qntm_012" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_off_qntm_013" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_off_qntm_014" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_check_to_off_qntm_015" android:tint="?attr/colorControlActivated" /> </item> </animation-list> </transition> diff --git a/core/res/res/drawable/btn_default_quantum.xml b/core/res/res/drawable/btn_default_quantum.xml index 63473a4..61193fe 100644 --- a/core/res/res/drawable/btn_default_quantum.xml +++ b/core/res/res/drawable/btn_default_quantum.xml @@ -17,20 +17,7 @@ <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:tint="?attr/colorControlHighlight"> <item> - <inset - android:insetLeft="4dp" - android:insetTop="4dp" - android:insetBottom="4dp" - android:insetRight="4dp"> - <shape android:shape="rectangle"> - <solid android:color="?attr/colorButtonNormal" /> - <corners android:radius="2dp" /> - <padding - android:left="4dp" - android:top="4dp" - android:bottom="4dp" - android:right="4dp" /> - </shape> - </inset> + <nine-patch android:src="@drawable/btn_qntm_alpha" + android:tint="?attr/colorButtonNormal" /> </item> </ripple> diff --git a/core/res/res/drawable/btn_radio_quantum.xml b/core/res/res/drawable/btn_radio_quantum.xml deleted file mode 100644 index 0f9ebce..0000000 --- a/core/res/res/drawable/btn_radio_quantum.xml +++ /dev/null @@ -1,36 +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="false" android:state_checked="true"> - <bitmap android:src="@drawable/btn_radio_on_qntm_alpha" - android:tint="?attr/colorControlNormal" - android:alpha="?attr/disabledAlpha" /> - </item> - <item android:state_enabled="false"> - <bitmap android:src="@drawable/btn_radio_off_qntm_alpha" - android:tint="?attr/colorControlNormal" - android:alpha="?attr/disabledAlpha" /> - </item> - <item android:state_checked="true"> - <bitmap android:src="@drawable/btn_radio_on_qntm_alpha" - android:tint="?attr/colorControlActivated" /> - </item> - <item> - <bitmap android:src="@drawable/btn_radio_off_qntm_alpha" - android:tint="?attr/colorControlNormal" /> - </item> -</selector> diff --git a/core/res/res/drawable/btn_radio_quantum_anim.xml b/core/res/res/drawable/btn_radio_quantum_anim.xml index 5068b7a..cd9b518 100644 --- a/core/res/res/drawable/btn_radio_quantum_anim.xml +++ b/core/res/res/drawable/btn_radio_quantum_anim.xml @@ -16,88 +16,118 @@ <animated-selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false" android:state_checked="true"> - <bitmap android:src="@drawable/btn_radio_anim_00015_qntm_alpha" - android:tint="?attr/colorControlActivated" - android:alpha="?attr/disabledAlpha" /> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_015" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" /> </item> <item android:state_enabled="false"> - <bitmap android:src="@drawable/btn_radio_anim_00000_qntm_alpha" - android:tint="?attr/colorControlNormal" - android:alpha="?attr/disabledAlpha" /> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_000" android:tint="?attr/colorControlNormal" android:alpha="?attr/disabledAlpha" /> </item> <item android:state_checked="true" android:id="@+id/on"> - <bitmap android:src="@drawable/btn_radio_anim_00015_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_015" android:tint="?attr/colorControlActivated" /> </item> <item android:id="@+id/off"> - <bitmap android:src="@drawable/btn_radio_anim_00000_qntm_alpha" - android:tint="?attr/colorControlNormal" /> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_000" android:tint="?attr/colorControlNormal" /> </item> - <transition android:fromId="@+id/off" android:toId="@+id/on" android:reversible="true"> + <transition android:fromId="@+id/off" android:toId="@+id/on"> <animation-list> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_radio_anim_00000_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_000" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_radio_anim_00001_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_001" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_radio_anim_00002_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_002" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_radio_anim_00003_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_003" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_radio_anim_00004_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_004" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_radio_anim_00005_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_005" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_radio_anim_00006_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_006" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_radio_anim_00007_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_007" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_radio_anim_00008_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_008" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_radio_anim_00009_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_009" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_radio_anim_00010_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_010" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_radio_anim_00011_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_011" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_radio_anim_00012_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_012" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_radio_anim_00013_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_013" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_radio_anim_00014_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_014" android:tint="?attr/colorControlActivated" /> </item> - <item android:duration="33"> - <bitmap android:src="@drawable/btn_radio_anim_00015_qntm_alpha" - android:tint="?attr/colorControlActivated" /> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_on_qntm_015" android:tint="?attr/colorControlActivated" /> + </item> + </animation-list> + </transition> + <transition android:fromId="@+id/on" android:toId="@+id/off"> + <animation-list> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_off_qntm_000" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_off_qntm_001" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_off_qntm_002" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_off_qntm_003" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_off_qntm_004" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_off_qntm_005" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_off_qntm_006" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_off_qntm_007" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_off_qntm_008" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_off_qntm_009" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_off_qntm_010" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_off_qntm_011" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_off_qntm_012" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_off_qntm_013" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_off_qntm_014" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_radio_to_off_qntm_015" android:tint="?attr/colorControlActivated" /> </item> </animation-list> </transition> diff --git a/core/res/res/drawable/btn_toggle_quantum.xml b/core/res/res/drawable/btn_toggle_quantum.xml new file mode 100644 index 0000000..e235598 --- /dev/null +++ b/core/res/res/drawable/btn_toggle_quantum.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2008 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<inset xmlns:android="http://schemas.android.com/apk/res/android" + android:insetLeft="4dp" + android:insetTop="4dp" + android:insetBottom="4dp" + android:insetRight="4dp"> + <layer-list android:paddingMode="stack"> + <item> + <ripple android:tint="?attr/colorControlHighlight"> + <item> + <nine-patch android:src="@drawable/btn_toggle_qntm_alpha" + android:tint="?attr/colorButtonNormal" /> + </item> + </ripple> + </item> + <item> + <selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_checked="false"> + <nine-patch android:src="@drawable/btn_toggle_indicator_qntm_alpha" + android:tint="?attr/colorControlNormal" /> + </item> + <item android:state_checked="true"> + <nine-patch android:src="@drawable/btn_toggle_indicator_qntm_alpha" + android:tint="?attr/colorControlActivated" /> + </item> + </selector> + </item> + </layer-list> +</inset> diff --git a/core/res/res/drawable/scrubber_control_quantum_anim.xml b/core/res/res/drawable/scrubber_control_quantum_anim.xml new file mode 100644 index 0000000..87d3ae9 --- /dev/null +++ b/core/res/res/drawable/scrubber_control_quantum_anim.xml @@ -0,0 +1,74 @@ +<?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. +--> + +<animated-selector xmlns:android="http://schemas.android.com/apk/res/android" android:constantSize="true"> + <item android:state_enabled="false" android:state_pressed="true"> + <bitmap android:src="@drawable/scrubber_control_off_qntm_alpha" android:gravity="center" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" /> + </item> + <item android:state_enabled="false"> + <bitmap android:src="@drawable/scrubber_control_off_qntm_alpha" android:gravity="center" android:tint="?attr/colorControlNormal" android:alpha="?attr/disabledAlpha" /> + </item> + <item android:state_pressed="true" android:id="@+id/pressed"> + <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_005" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:id="@+id/not_pressed"> + <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_000" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <transition android:fromId="@+id/not_pressed" android:toId="@+id/pressed"> + <animation-list> + <item android:duration="15"> + <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_000" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_001" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_002" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_003" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_004" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_005" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + </animation-list> + </transition> + <transition android:fromId="@+id/pressed" android:toId="@+id/not_pressed"> + <animation-list> + <item android:duration="15"> + <bitmap android:src="@drawable/scrubber_control_from_pressed_qntm_000" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/scrubber_control_from_pressed_qntm_001" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/scrubber_control_from_pressed_qntm_002" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/scrubber_control_from_pressed_qntm_003" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/scrubber_control_from_pressed_qntm_004" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/scrubber_control_from_pressed_qntm_005" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + </animation-list> + </transition> +</animated-selector> diff --git a/core/res/res/drawable/switch_inner_quantum.xml b/core/res/res/drawable/switch_inner_quantum.xml deleted file mode 100644 index 856895e..0000000 --- a/core/res/res/drawable/switch_inner_quantum.xml +++ /dev/null @@ -1,36 +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="false" android:state_checked="true"> - <nine-patch android:src="@drawable/switch_on_qntm_alpha" - android:tint="?attr/colorControlNormal" - android:alpha="?attr/disabledAlpha" /> - </item> - <item android:state_enabled="false"> - <nine-patch android:src="@drawable/switch_off_qntm_alpha" - android:tint="?attr/colorControlNormal" - android:alpha="?attr/disabledAlpha" /> - </item> - <item android:state_checked="true"> - <nine-patch android:src="@drawable/switch_on_qntm_alpha" - android:tint="?attr/colorControlActivated" /> - </item> - <item> - <nine-patch android:src="@drawable/switch_off_qntm_alpha" - android:tint="?attr/colorControlNormal" /> - </item> -</selector> diff --git a/core/res/res/drawable/switch_thumb_quantum_anim.xml b/core/res/res/drawable/switch_thumb_quantum_anim.xml new file mode 100644 index 0000000..1984d47 --- /dev/null +++ b/core/res/res/drawable/switch_thumb_quantum_anim.xml @@ -0,0 +1,128 @@ +<?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. +--> + +<animated-selector xmlns:android="http://schemas.android.com/apk/res/android" android:constantSize="true"> + <item android:state_enabled="false" android:state_checked="true"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_014" android:gravity="center" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" /> + </item> + <item android:state_enabled="false"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_000" android:gravity="center" android:tint="?attr/colorControlNormal" android:alpha="?attr/disabledAlpha" /> + </item> + <item android:state_checked="true" android:id="@+id/on"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_014" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:id="@+id/off"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_000" android:gravity="center" android:tint="?attr/colorControlNormal" /> + </item> + <transition android:fromId="@+id/off" android:toId="@+id/on"> + <animation-list> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_000" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_001" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_002" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_003" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_004" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_005" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_006" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_007" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_008" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_009" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_010" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_011" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_012" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_013" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_on_qntm_014" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + </animation-list> + </transition> + <transition android:fromId="@+id/on" android:toId="@+id/off"> + <animation-list> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_off_qntm_000" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_off_qntm_001" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_off_qntm_002" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_off_qntm_003" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_off_qntm_004" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_off_qntm_005" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_off_qntm_006" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_off_qntm_007" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_off_qntm_008" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_off_qntm_009" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_off_qntm_010" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_off_qntm_011" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_off_qntm_012" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_off_qntm_013" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + <item android:duration="15"> + <bitmap android:src="@drawable/btn_switch_to_off_qntm_014" android:gravity="center" android:tint="?attr/colorControlActivated" /> + </item> + </animation-list> + </transition> +</animated-selector> diff --git a/core/res/res/drawable/switch_track_quantum.xml b/core/res/res/drawable/switch_track_quantum.xml index 8c4e6b71..3651a0a 100644 --- a/core/res/res/drawable/switch_track_quantum.xml +++ b/core/res/res/drawable/switch_track_quantum.xml @@ -15,6 +15,16 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" android:state_checked="true"> + <nine-patch android:src="@drawable/switch_track_qntm_alpha" + android:tint="?attr/colorControlActivated" + android:alpha="?attr/disabledAlpha" /> + </item> + <item android:state_enabled="false"> + <nine-patch android:src="@drawable/switch_track_qntm_alpha" + android:tint="?attr/colorControlNormal" + android:alpha="?attr/disabledAlpha" /> + </item> <item android:state_checked="true"> <nine-patch android:src="@drawable/switch_track_qntm_alpha" android:tint="?attr/colorControlActivated" /> diff --git a/core/res/res/values/dimens_quantum.xml b/core/res/res/values/dimens_quantum.xml index 53e97fd..2defee2 100644 --- a/core/res/res/values/dimens_quantum.xml +++ b/core/res/res/values/dimens_quantum.xml @@ -47,6 +47,10 @@ <dimen name="text_size_menu_quantum">14sp</dimen> <dimen name="text_size_button_quantum">14sp</dimen> + <dimen name="text_size_large_quantum">22sp</dimen> + <dimen name="text_size_medium_quantum">18sp</dimen> + <dimen name="text_size_small_quantum">14sp</dimen> + <dimen name="floating_window_z">16dp</dimen> <dimen name="floating_window_margin">32dp</dimen> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 4a27ebe..f6cd9e8 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -277,37 +277,6 @@ please see styles_device_defaults.xml. <item name="android:textColor">#CCCCCC</item> </style> - <style name="TextAppearance.StatusBar.Quantum"> - </style> - <style name="TextAppearance.StatusBar.Quantum.EventContent"> - <item name="android:textColor">#90000000</item> - <item name="android:textSize">@dimen/notification_text_size</item> - </style> - <style name="TextAppearance.StatusBar.Quantum.EventContent.Title"> - <item name="android:textColor">#DD000000</item> - <item name="android:textSize">@dimen/notification_title_text_size</item> - </style> - <style name="TextAppearance.StatusBar.Quantum.EventContent.Line2"> - <item name="android:textSize">@dimen/notification_subtext_size</item> - </style> - <style name="TextAppearance.StatusBar.Quantum.EventContent.Info"> - <item name="android:textSize">@dimen/notification_subtext_size</item> - </style> - <style name="TextAppearance.StatusBar.Quantum.EventContent.Time"> - <item name="android:textSize">@dimen/notification_subtext_size</item> - </style> - <style name="TextAppearance.StatusBar.Quantum.EventContent.Emphasis"> - <item name="android:textColor">#66000000</item> - </style> - <style name="Widget.StatusBar.Quantum.ProgressBar" - parent="Widget.Quantum.Light.ProgressBar.Horizontal"> - <item name="android:progressDrawable">@drawable/notification_quantum_media_progress</item> - </style> - - <style name="Widget.StatusBar.Quantum.ProgressBar" - parent="Widget.Quantum.Light.ProgressBar.Horizontal"> - </style> - <style name="TextAppearance.Small.CalendarViewWeekDayView"> <item name="android:textStyle">bold</item> </style> diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml index e528278..2e7a5b1 100644 --- a/core/res/res/values/styles_quantum.xml +++ b/core/res/res/values/styles_quantum.xml @@ -182,7 +182,10 @@ please see styles_device_defaults.xml. <item name="textColorLink">?attr/textColorLinkInverse</item> </style> - <style name="TextAppearance.Quantum.Large" parent="TextAppearance.Quantum.Headline" /> + <style name="TextAppearance.Quantum.Large"> + <item name="textSize">@dimen/text_size_large_quantum</item> + <item name="textColor">?attr/textColorPrimary</item> + </style> <style name="TextAppearance.Quantum.Large.Inverse"> <item name="textColor">?attr/textColorPrimaryInverse</item> @@ -191,7 +194,10 @@ please see styles_device_defaults.xml. <item name="textColorLink">?attr/textColorLinkInverse</item> </style> - <style name="TextAppearance.Quantum.Medium" parent="TextAppearance.Quantum.Body1" /> + <style name="TextAppearance.Quantum.Medium"> + <item name="textSize">@dimen/text_size_medium_quantum</item> + <item name="textColor">?attr/textColorSecondary</item> + </style> <style name="TextAppearance.Quantum.Medium.Inverse"> <item name="textColor">?attr/textColorSecondaryInverse</item> @@ -200,7 +206,10 @@ please see styles_device_defaults.xml. <item name="textColorLink">?attr/textColorLinkInverse</item> </style> - <style name="TextAppearance.Quantum.Small" parent="TextAppearance.Quantum.Caption" /> + <style name="TextAppearance.Quantum.Small"> + <item name="textSize">@dimen/text_size_small_quantum</item> + <item name="textColor">?attr/textColorTertiary</item> + </style> <style name="TextAppearance.Quantum.Small.Inverse"> <item name="textColor">?attr/textColorTertiaryInverse</item> @@ -351,6 +360,38 @@ please see styles_device_defaults.xml. <item name="textStyle">bold</item> </style> + <style name="TextAppearance.StatusBar.Quantum" /> + + <style name="TextAppearance.StatusBar.Quantum.EventContent"> + <item name="android:textColor">#90000000</item> + <item name="android:textSize">@dimen/notification_text_size</item> + </style> + + <style name="TextAppearance.StatusBar.Quantum.EventContent.Title"> + <item name="android:textColor">#DD000000</item> + <item name="android:textSize">@dimen/notification_title_text_size</item> + </style> + + <style name="TextAppearance.StatusBar.Quantum.EventContent.Line2"> + <item name="android:textSize">@dimen/notification_subtext_size</item> + </style> + + <style name="TextAppearance.StatusBar.Quantum.EventContent.Info"> + <item name="android:textSize">@dimen/notification_subtext_size</item> + </style> + + <style name="TextAppearance.StatusBar.Quantum.EventContent.Time"> + <item name="android:textSize">@dimen/notification_subtext_size</item> + </style> + + <style name="TextAppearance.StatusBar.Quantum.EventContent.Emphasis"> + <item name="android:textColor">#66000000</item> + </style> + + <style name="Widget.StatusBar.Quantum.ProgressBar" parent="Widget.Quantum.Light.ProgressBar.Horizontal"> + <item name="android:progressDrawable">@drawable/notification_quantum_media_progress</item> + </style> + <!-- Widget Styles --> <style name="Quantum"/> @@ -390,7 +431,7 @@ please see styles_device_defaults.xml. </style> <style name="Widget.Quantum.Button.Toggle"> - <item name="background">@drawable/btn_toggle_holo_dark</item> + <item name="background">@drawable/btn_toggle_quantum</item> <item name="textOn">@string/capital_on</item> <item name="textOff">@string/capital_off</item> <item name="textAppearance">?attr/textAppearanceSmall</item> @@ -459,13 +500,13 @@ please see styles_device_defaults.xml. <style name="Widget.Quantum.CompoundButton.Switch"> <item name="track">@drawable/switch_track_quantum</item> - <item name="thumb">@drawable/switch_inner_quantum</item> + <item name="thumb">@drawable/switch_thumb_quantum_anim</item> <item name="splitTrack">true</item> <item name="switchTextAppearance">@style/TextAppearance.Quantum.Widget.Switch</item> <item name="textOn"></item> <item name="textOff"></item> - <item name="switchMinWidth">72dip</item> - <item name="switchPadding">16dip</item> + <item name="switchMinWidth">4dip</item> + <item name="switchPadding">4dip</item> <item name="background">?attr/selectableItemBackground</item> </style> @@ -579,7 +620,7 @@ please see styles_device_defaults.xml. <item name="indeterminateOnly">false</item> <item name="progressDrawable">@drawable/scrubber_progress_horizontal_quantum</item> <item name="indeterminateDrawable">@drawable/scrubber_progress_horizontal_quantum</item> - <item name="thumb">@drawable/scrubber_control_selector_quantum</item> + <item name="thumb">@drawable/scrubber_control_quantum_anim</item> <item name="splitTrack">true</item> <item name="focusable">true</item> <item name="paddingStart">16dip</item> @@ -784,15 +825,7 @@ please see styles_device_defaults.xml. <style name="Widget.Quantum.Light.Button.Borderless" parent="Widget.Quantum.Button.Borderless"/> <style name="Widget.Quantum.Light.Button.Borderless.Small" parent="Widget.Quantum.Button.Borderless.Small"/> <style name="Widget.Quantum.Light.Button.Inset" parent="Widget.Quantum.Button.Inset"/> - - <style name="Widget.Quantum.Light.Button.Toggle"> - <item name="background">@drawable/btn_toggle_holo_light</item> - <item name="textOn">@string/capital_on</item> - <item name="textOff">@string/capital_off</item> - <item name="textAppearance">?attr/textAppearanceSmall</item> - <item name="minHeight">48dip</item> - </style> - + <style name="Widget.Quantum.Light.Button.Toggle" parent="Widget.Quantum.Button.Toggle" /> <style name="Widget.Quantum.Light.ButtonBar" parent="Widget.Quantum.ButtonBar"/> <style name="Widget.Quantum.Light.ButtonBar.AlertDialog" parent="Widget.Quantum.ButtonBar.AlertDialog"/> diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk index 452c575..c6bccfe 100644 --- a/data/fonts/Android.mk +++ b/data/fonts/Android.mk @@ -105,8 +105,11 @@ font_src_files := \ ifeq ($(MINIMAL_FONT_FOOTPRINT),true) +$(eval $(call create-font-symlink,Roboto-Black.ttf,Roboto-Bold.ttf)) $(eval $(call create-font-symlink,Roboto-Light.ttf,Roboto-Regular.ttf)) $(eval $(call create-font-symlink,Roboto-LightItalic.ttf,Roboto-Italic.ttf)) +$(eval $(call create-font-symlink,Roboto-Medium.ttf,Roboto-Regular.ttf)) +$(eval $(call create-font-symlink,Roboto-MediumItalic.ttf,Roboto-Italic.ttf)) $(eval $(call create-font-symlink,Roboto-Thin.ttf,Roboto-Regular.ttf)) $(eval $(call create-font-symlink,Roboto-ThinItalic.ttf,Roboto-Italic.ttf)) $(eval $(call create-font-symlink,RobotoCondensed-Regular.ttf,Roboto-Regular.ttf)) @@ -116,8 +119,11 @@ $(eval $(call create-font-symlink,RobotoCondensed-BoldItalic.ttf,Roboto-BoldItal else # !MINIMAL_FONT font_src_files += \ + Roboto-Black.ttf \ Roboto-Light.ttf \ Roboto-LightItalic.ttf \ + Roboto-Medium.ttf \ + Roboto-MediumItalic.ttf \ Roboto-Thin.ttf \ Roboto-ThinItalic.ttf \ RobotoCondensed-Regular.ttf \ diff --git a/data/fonts/Roboto-Black.ttf b/data/fonts/Roboto-Black.ttf Binary files differnew file mode 100644 index 0000000..2cdbe43 --- /dev/null +++ b/data/fonts/Roboto-Black.ttf diff --git a/data/fonts/Roboto-Bold.ttf b/data/fonts/Roboto-Bold.ttf Binary files differindex c5b9c67..15c9b4e 100644 --- a/data/fonts/Roboto-Bold.ttf +++ b/data/fonts/Roboto-Bold.ttf diff --git a/data/fonts/Roboto-BoldItalic.ttf b/data/fonts/Roboto-BoldItalic.ttf Binary files differindex 0320214..a0abf30 100644 --- a/data/fonts/Roboto-BoldItalic.ttf +++ b/data/fonts/Roboto-BoldItalic.ttf diff --git a/data/fonts/Roboto-Italic.ttf b/data/fonts/Roboto-Italic.ttf Binary files differindex 38ba570..67b5394 100644 --- a/data/fonts/Roboto-Italic.ttf +++ b/data/fonts/Roboto-Italic.ttf diff --git a/data/fonts/Roboto-Light.ttf b/data/fonts/Roboto-Light.ttf Binary files differindex 271606b..d9fb64a 100644 --- a/data/fonts/Roboto-Light.ttf +++ b/data/fonts/Roboto-Light.ttf diff --git a/data/fonts/Roboto-LightItalic.ttf b/data/fonts/Roboto-LightItalic.ttf Binary files differindex 17ef355..1fd1d31 100644 --- a/data/fonts/Roboto-LightItalic.ttf +++ b/data/fonts/Roboto-LightItalic.ttf diff --git a/data/fonts/Roboto-Medium.ttf b/data/fonts/Roboto-Medium.ttf Binary files differnew file mode 100644 index 0000000..c63c115 --- /dev/null +++ b/data/fonts/Roboto-Medium.ttf diff --git a/data/fonts/Roboto-MediumItalic.ttf b/data/fonts/Roboto-MediumItalic.ttf Binary files differnew file mode 100644 index 0000000..cd7c835 --- /dev/null +++ b/data/fonts/Roboto-MediumItalic.ttf diff --git a/data/fonts/Roboto-Regular.ttf b/data/fonts/Roboto-Regular.ttf Binary files differindex 7469063..9cb4a5a 100644 --- a/data/fonts/Roboto-Regular.ttf +++ b/data/fonts/Roboto-Regular.ttf diff --git a/data/fonts/Roboto-Thin.ttf b/data/fonts/Roboto-Thin.ttf Binary files differindex 74efe4d..f02f100 100644 --- a/data/fonts/Roboto-Thin.ttf +++ b/data/fonts/Roboto-Thin.ttf diff --git a/data/fonts/Roboto-ThinItalic.ttf b/data/fonts/Roboto-ThinItalic.ttf Binary files differindex f08ea51..12a2ce0 100644 --- a/data/fonts/Roboto-ThinItalic.ttf +++ b/data/fonts/Roboto-ThinItalic.ttf diff --git a/data/fonts/RobotoCondensed-Bold.ttf b/data/fonts/RobotoCondensed-Bold.ttf Binary files differindex 1252d00..1079af6 100644 --- a/data/fonts/RobotoCondensed-Bold.ttf +++ b/data/fonts/RobotoCondensed-Bold.ttf diff --git a/data/fonts/RobotoCondensed-BoldItalic.ttf b/data/fonts/RobotoCondensed-BoldItalic.ttf Binary files differindex e914a07..e7f13c2 100644 --- a/data/fonts/RobotoCondensed-BoldItalic.ttf +++ b/data/fonts/RobotoCondensed-BoldItalic.ttf diff --git a/data/fonts/RobotoCondensed-Italic.ttf b/data/fonts/RobotoCondensed-Italic.ttf Binary files differindex 8a570cf..7fa0448 100644 --- a/data/fonts/RobotoCondensed-Italic.ttf +++ b/data/fonts/RobotoCondensed-Italic.ttf diff --git a/data/fonts/RobotoCondensed-Light.ttf b/data/fonts/RobotoCondensed-Light.ttf Binary files differindex 41d212a..96b75dd 100644 --- a/data/fonts/RobotoCondensed-Light.ttf +++ b/data/fonts/RobotoCondensed-Light.ttf diff --git a/data/fonts/RobotoCondensed-LightItalic.ttf b/data/fonts/RobotoCondensed-LightItalic.ttf Binary files differindex dd54971..7a2c164 100755..100644 --- a/data/fonts/RobotoCondensed-LightItalic.ttf +++ b/data/fonts/RobotoCondensed-LightItalic.ttf diff --git a/data/fonts/RobotoCondensed-Regular.ttf b/data/fonts/RobotoCondensed-Regular.ttf Binary files differindex a16b9cb..734cc40 100644 --- a/data/fonts/RobotoCondensed-Regular.ttf +++ b/data/fonts/RobotoCondensed-Regular.ttf diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk index 2312a04..e5573bb 100644 --- a/data/fonts/fonts.mk +++ b/data/fonts/fonts.mk @@ -24,8 +24,11 @@ PRODUCT_PACKAGES := \ Roboto-Bold.ttf \ Roboto-Italic.ttf \ Roboto-BoldItalic.ttf \ + Roboto-Black.ttf \ Roboto-Light.ttf \ Roboto-LightItalic.ttf \ + Roboto-Medium.ttf \ + Roboto-MediumItalic.ttf \ Roboto-Thin.ttf \ Roboto-ThinItalic.ttf \ RobotoCondensed-Regular.ttf \ diff --git a/data/fonts/system_fonts.xml b/data/fonts/system_fonts.xml index 97b7fd8..646b33b 100644 --- a/data/fonts/system_fonts.xml +++ b/data/fonts/system_fonts.xml @@ -68,6 +68,25 @@ <family> <nameset> + <name>sans-serif-medium</name> + </nameset> + <fileset> + <file>Roboto-Medium.ttf</file> + <file>Roboto-MediumItalic.ttf</file> + </fileset> + </family> + + <family> + <nameset> + <name>sans-serif-black</name> + </nameset> + <fileset> + <file>Roboto-Black.ttf</file> + </fileset> + </family> + + <family> + <nameset> <name>sans-serif-condensed-light</name> </nameset> <fileset> diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java index b7673d8..3ab57c1 100644 --- a/graphics/java/android/graphics/BitmapShader.java +++ b/graphics/java/android/graphics/BitmapShader.java @@ -44,7 +44,6 @@ public class BitmapShader extends Shader { mTileY = tileY; final long b = bitmap.ni(); native_instance = nativeCreate(b, tileX.nativeInt, tileY.nativeInt); - native_shader = nativePostCreate(native_instance, b, tileX.nativeInt, tileY.nativeInt); } /** @@ -59,6 +58,4 @@ public class BitmapShader extends Shader { private static native long nativeCreate(long native_bitmap, int shaderTileModeX, int shaderTileModeY); - private static native long nativePostCreate(long native_shader, long native_bitmap, - int shaderTileModeX, int shaderTileModeY); } diff --git a/graphics/java/android/graphics/ComposeShader.java b/graphics/java/android/graphics/ComposeShader.java index 5109ffd..d7b2071 100644 --- a/graphics/java/android/graphics/ComposeShader.java +++ b/graphics/java/android/graphics/ComposeShader.java @@ -55,14 +55,6 @@ public class ComposeShader extends Shader { mXferMode = mode; native_instance = nativeCreate1(shaderA.native_instance, shaderB.native_instance, (mode != null) ? mode.native_instance : 0); - if (mode instanceof PorterDuffXfermode) { - PorterDuff.Mode pdMode = ((PorterDuffXfermode) mode).mode; - native_shader = nativePostCreate2(native_instance, shaderA.native_shader, - shaderB.native_shader, pdMode != null ? pdMode.nativeInt : 0); - } else { - native_shader = nativePostCreate1(native_instance, shaderA.native_shader, - shaderB.native_shader, mode != null ? mode.native_instance : 0); - } } /** Create a new compose shader, given shaders A, B, and a combining PorterDuff mode. @@ -79,8 +71,6 @@ public class ComposeShader extends Shader { mPorterDuffMode = mode; native_instance = nativeCreate2(shaderA.native_instance, shaderB.native_instance, mode.nativeInt); - native_shader = nativePostCreate2(native_instance, shaderA.native_shader, - shaderB.native_shader, mode.nativeInt); } /** @@ -108,8 +98,4 @@ public class ComposeShader extends Shader { long native_mode); private static native long nativeCreate2(long native_shaderA, long native_shaderB, int porterDuffMode); - private static native long nativePostCreate1(long native_shader, long native_skiaShaderA, - long native_skiaShaderB, long native_mode); - private static native long nativePostCreate2(long native_shader, long native_skiaShaderA, - long native_skiaShaderB, int porterDuffMode); } diff --git a/graphics/java/android/graphics/LinearGradient.java b/graphics/java/android/graphics/LinearGradient.java index 0eae67c..90cb217 100644 --- a/graphics/java/android/graphics/LinearGradient.java +++ b/graphics/java/android/graphics/LinearGradient.java @@ -66,8 +66,6 @@ public class LinearGradient extends Shader { mPositions = positions; mTileMode = tile; native_instance = nativeCreate1(x0, y0, x1, y1, colors, positions, tile.nativeInt); - native_shader = nativePostCreate1(native_instance, x0, y0, x1, y1, colors, positions, - tile.nativeInt); } /** Create a shader that draws a linear gradient along a line. @@ -90,8 +88,6 @@ public class LinearGradient extends Shader { mColor1 = color1; mTileMode = tile; native_instance = nativeCreate2(x0, y0, x1, y1, color0, color1, tile.nativeInt); - native_shader = nativePostCreate2(native_instance, x0, y0, x1, y1, color0, color1, - tile.nativeInt); } /** @@ -120,8 +116,4 @@ public class LinearGradient extends Shader { int colors[], float positions[], int tileMode); private native long nativeCreate2(float x0, float y0, float x1, float y1, int color0, int color1, int tileMode); - private native long nativePostCreate1(long native_shader, float x0, float y0, float x1, float y1, - int colors[], float positions[], int tileMode); - private native long nativePostCreate2(long native_shader, float x0, float y0, float x1, float y1, - int color0, int color1, int tileMode); } diff --git a/graphics/java/android/graphics/RadialGradient.java b/graphics/java/android/graphics/RadialGradient.java index c00c612..75c951a 100644 --- a/graphics/java/android/graphics/RadialGradient.java +++ b/graphics/java/android/graphics/RadialGradient.java @@ -66,8 +66,6 @@ public class RadialGradient extends Shader { mPositions = positions; mTileMode = tile; native_instance = nativeCreate1(x, y, radius, colors, positions, tile.nativeInt); - native_shader = nativePostCreate1(native_instance, x, y, radius, colors, positions, - tile.nativeInt); } /** Create a shader that draws a radial gradient given the center and radius. @@ -91,8 +89,6 @@ public class RadialGradient extends Shader { mColor1 = color1; mTileMode = tile; native_instance = nativeCreate2(x, y, radius, color0, color1, tile.nativeInt); - native_shader = nativePostCreate2(native_instance, x, y, radius, color0, color1, - tile.nativeInt); } /** @@ -121,10 +117,5 @@ public class RadialGradient extends Shader { int colors[], float positions[], int tileMode); private static native long nativeCreate2(float x, float y, float radius, int color0, int color1, int tileMode); - - private static native long nativePostCreate1(long native_shader, float x, float y, float radius, - int colors[], float positions[], int tileMode); - private static native long nativePostCreate2(long native_shader, float x, float y, float radius, - int color0, int color1, int tileMode); } diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java index 94b4c4a..6870ab4 100644 --- a/graphics/java/android/graphics/Shader.java +++ b/graphics/java/android/graphics/Shader.java @@ -29,10 +29,6 @@ public class Shader { * @hide */ public long native_instance; - /** - * @hide - */ - public long native_shader; private Matrix mLocalMatrix; @@ -78,7 +74,7 @@ public class Shader { */ public void setLocalMatrix(Matrix localM) { mLocalMatrix = localM; - nativeSetLocalMatrix(native_instance, native_shader, + nativeSetLocalMatrix(native_instance, localM == null ? 0 : localM.native_instance); } @@ -86,7 +82,7 @@ public class Shader { try { super.finalize(); } finally { - nativeDestructor(native_instance, native_shader); + nativeDestructor(native_instance); } } @@ -112,7 +108,7 @@ public class Shader { } } - private static native void nativeDestructor(long native_shader, long native_skiaShader); + private static native void nativeDestructor(long native_shader); private static native void nativeSetLocalMatrix(long native_shader, - long native_skiaShader, long matrix_instance); + long matrix_instance); } diff --git a/graphics/java/android/graphics/SweepGradient.java b/graphics/java/android/graphics/SweepGradient.java index 21239f7..18a748f 100644 --- a/graphics/java/android/graphics/SweepGradient.java +++ b/graphics/java/android/graphics/SweepGradient.java @@ -63,7 +63,6 @@ public class SweepGradient extends Shader { mColors = colors; mPositions = positions; native_instance = nativeCreate1(cx, cy, colors, positions); - native_shader = nativePostCreate1(native_instance, cx, cy, colors, positions); } /** @@ -81,7 +80,6 @@ public class SweepGradient extends Shader { mColor0 = color0; mColor1 = color1; native_instance = nativeCreate2(cx, cy, color0, color1); - native_shader = nativePostCreate2(native_instance, cx, cy, color0, color1); } /** @@ -108,10 +106,5 @@ public class SweepGradient extends Shader { private static native long nativeCreate1(float x, float y, int colors[], float positions[]); private static native long nativeCreate2(float x, float y, int color0, int color1); - - private static native long nativePostCreate1(long native_shader, float cx, float cy, - int[] colors, float[] positions); - private static native long nativePostCreate2(long native_shader, float cx, float cy, - int color0, int color1); } diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java index 46e3401..42872e9 100644 --- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java @@ -80,6 +80,22 @@ public class AnimatedStateListDrawable extends StateListDrawable { this(null, null); } + @Override + public boolean setVisible(boolean visible, boolean restart) { + final boolean changed = super.setVisible(visible, restart); + if (mAnim != null) { + if (visible) { + if (changed || restart) { + // TODO: Should this support restart? + mAnim.end(); + } + } else { + mAnim.end(); + } + } + return changed; + } + /** * Add a new drawable to the set of keyframes. * diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index f3fcf2c..c95ac82 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -25,6 +25,7 @@ import android.graphics.BitmapFactory; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.ColorFilter; +import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PixelFormat; @@ -92,6 +93,9 @@ public class BitmapDrawable extends Drawable { private int mBitmapWidth; private int mBitmapHeight; + /** Optical insets due to gravity. */ + private Insets mOpticalInsets = null; + // Mirroring matrix for using with Shaders private Matrix mMirrorMatrix; @@ -456,9 +460,9 @@ public class BitmapDrawable extends Drawable { @Override protected void onBoundsChange(Rect bounds) { - super.onBoundsChange(bounds); mApplyGravity = true; - Shader shader = mBitmapState.mPaint.getShader(); + + final Shader shader = mBitmapState.mPaint.getShader(); if (shader != null) { if (needMirroring()) { updateMirrorMatrix(bounds.right - bounds.left); @@ -517,9 +521,7 @@ public class BitmapDrawable extends Drawable { final boolean needMirroring = needMirroring(); if (shader == null) { if (mApplyGravity) { - final int layoutDirection = getLayoutDirection(); - Gravity.apply(state.mGravity, mBitmapWidth, mBitmapHeight, - getBounds(), mDstRect, layoutDirection); + applyGravity(); mApplyGravity = false; } @@ -564,6 +566,31 @@ public class BitmapDrawable extends Drawable { } } + /** + * @hide + */ + @Override + public Insets getOpticalInsets() { + if (mApplyGravity && mBitmapState.mPaint.getShader() == null) { + applyGravity(); + mApplyGravity = false; + } + return mOpticalInsets == null ? Insets.NONE : mOpticalInsets; + } + + private void applyGravity() { + final Rect bounds = getBounds(); + final int layoutDirection = getLayoutDirection(); + Gravity.apply(mBitmapState.mGravity, mBitmapWidth, mBitmapHeight, + bounds, mDstRect, layoutDirection); + + final int left = mDstRect.left - bounds.left; + final int top = mDstRect.top - bounds.top; + final int right = bounds.right - mDstRect.right; + final int bottom = bounds.bottom - mDstRect.bottom; + mOpticalInsets = Insets.of(left, top, right, bottom); + } + @Override public void setAlpha(int alpha) { final int oldAlpha = mBitmapState.mPaint.getAlpha(); diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index 04373d4..2aef39f 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -187,6 +187,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } if (mCurrDrawable != null) { mCurrDrawable.setBounds(bounds); + + // Must obtain optical insets after setting bounds. + mInsets = mCurrDrawable.getOpticalInsets(); } } @@ -385,7 +388,6 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mCurrDrawable = d; mCurIndex = idx; if (d != null) { - mInsets = d.getOpticalInsets(); d.mutate(); if (mDrawableContainerState.mEnterFadeDuration > 0) { mEnterAnimationEnd = now + mDrawableContainerState.mEnterFadeDuration; @@ -402,6 +404,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { d.setBounds(getBounds()); d.setLayoutDirection(getLayoutDirection()); d.setAutoMirrored(mDrawableContainerState.mAutoMirrored); + + // Must obtain optical insets after setting bounds. + mInsets = d.getOpticalInsets(); } else { mInsets = Insets.NONE; } diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index e3ed75e..e2bd50d 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -159,7 +159,8 @@ public class VectorDrawable extends Drawable { @Override public void setColorFilter(ColorFilter colorFilter) { - // TODO: support color filter + mVectorState.mVPathRenderer.setColorFilter(colorFilter); + invalidateSelf(); } @Override @@ -365,14 +366,15 @@ public class VectorDrawable extends Drawable { private VPath[] mCurrentPaths; private Paint mStrokePaint; private Paint mFillPaint; + private ColorFilter mColorFilter; private PathMeasure mPathMeasure; private VGroup mCurrentGroup = new VGroup(); - float mBaseWidth = 1; - float mBaseHeight = 1; - float mViewportWidth; - float mViewportHeight; + float mBaseWidth = 0; + float mBaseHeight = 0; + float mViewportWidth = 0; + float mViewportHeight = 0; public VPathRenderer() { } @@ -413,6 +415,18 @@ public class VectorDrawable extends Drawable { } } + public void setColorFilter(ColorFilter colorFilter) { + mColorFilter = colorFilter; + + if (mFillPaint != null) { + mFillPaint.setColorFilter(colorFilter); + } + + if (mStrokePaint != null) { + mStrokePaint.setColorFilter(colorFilter); + } + } + public void draw(Canvas canvas, int w, int h) { if (mCurrentPaths == null) { Log.e(LOGTAG,"mCurrentPaths == null"); @@ -470,6 +484,7 @@ public class VectorDrawable extends Drawable { if (vPath.mFillColor != 0) { if (mFillPaint == null) { mFillPaint = new Paint(); + mFillPaint.setColorFilter(mColorFilter); mFillPaint.setStyle(Paint.Style.FILL); mFillPaint.setAntiAlias(true); } @@ -481,6 +496,7 @@ public class VectorDrawable extends Drawable { if (vPath.mStrokeColor != 0) { if (mStrokePaint == null) { mStrokePaint = new Paint(); + mStrokePaint.setColorFilter(mColorFilter); mStrokePaint.setStyle(Paint.Style.STROKE); mStrokePaint.setAntiAlias(true); } @@ -516,24 +532,34 @@ public class VectorDrawable extends Drawable { private void parseViewport(Resources r, AttributeSet attrs) throws XmlPullParserException { final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport); - mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, 0); - mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, 0); - if (mViewportWidth == 0 || mViewportHeight == 0) { - throw new XmlPullParserException(a.getPositionDescription()+ - "<viewport> tag requires viewportWidth & viewportHeight to be set"); + mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, mViewportWidth); + mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, mViewportHeight); + + if (mViewportWidth <= 0) { + throw new XmlPullParserException(a.getPositionDescription() + + "<viewport> tag requires viewportWidth > 0"); + } else if (mViewportHeight <= 0) { + throw new XmlPullParserException(a.getPositionDescription() + + "<viewport> tag requires viewportHeight > 0"); } + a.recycle(); } private void parseSize(Resources r, AttributeSet attrs) throws XmlPullParserException { final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize); - mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, 0); - mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, 0); - if (mBaseWidth == 0 || mBaseHeight == 0) { - throw new XmlPullParserException(a.getPositionDescription()+ - "<size> tag requires width & height to be set"); + mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, mBaseWidth); + mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, mBaseHeight); + + if (mBaseWidth <= 0) { + throw new XmlPullParserException(a.getPositionDescription() + + "<size> tag requires width > 0"); + } else if (mBaseHeight <= 0) { + throw new XmlPullParserException(a.getPositionDescription() + + "<size> tag requires height > 0"); } + a.recycle(); } diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index 2e2ee15..5367663 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -33,6 +33,7 @@ #include "thread/TaskManager.h" #include "AssetAtlas.h" +#include "Extensions.h" #include "FontRenderer.h" #include "GammaFontRenderer.h" #include "TextureCache.h" diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp index 3016814..937bf8d 100644 --- a/libs/hwui/DeferredDisplayList.cpp +++ b/libs/hwui/DeferredDisplayList.cpp @@ -230,6 +230,11 @@ public: return false; } + if (op->mPaint && mOps[0].op->mPaint && + op->mPaint->getShader() != mOps[0].op->mPaint->getShader()) { + return false; + } + /* Draw Modifiers compatibility check * * Shadows are ignored, as only text uses them, and in that case they are drawn @@ -244,7 +249,6 @@ public: */ const DrawModifiers& lhsMod = lhs->mDrawModifiers; const DrawModifiers& rhsMod = rhs->mDrawModifiers; - if (lhsMod.mShader != rhsMod.mShader) return false; // Draw filter testing expects bit fields to be clear if filter not set. if (lhsMod.mHasDrawFilter != rhsMod.mHasDrawFilter) return false; diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index dac86cb..96c6292 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -58,11 +58,6 @@ void DisplayListData::cleanupResources() { caches.resourceCache.decrementRefcountLocked(patchResources.itemAt(i)); } - for (size_t i = 0; i < shaders.size(); i++) { - caches.resourceCache.decrementRefcountLocked(shaders.itemAt(i)); - caches.resourceCache.destructorLocked(shaders.itemAt(i)); - } - for (size_t i = 0; i < sourcePaths.size(); i++) { caches.resourceCache.decrementRefcountLocked(sourcePaths.itemAt(i)); } @@ -92,7 +87,6 @@ void DisplayListData::cleanupResources() { bitmapResources.clear(); ownedBitmapResources.clear(); patchResources.clear(); - shaders.clear(); sourcePaths.clear(); paints.clear(); regions.clear(); diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index b2ead5b..11e78b0 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -56,7 +56,6 @@ class DisplayListRenderer; class OpenGLRenderer; class Rect; class Layer; -class SkiaShader; class ClipRectOp; class SaveLayerOp; @@ -127,7 +126,6 @@ public: SortedVector<const SkPath*> sourcePaths; Vector<const SkRegion*> regions; Vector<const SkMatrix*> matrices; - Vector<SkiaShader*> shaders; Vector<Layer*> layers; uint32_t functorCount; bool hasDrawOps; diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index e4867220..ea3e7a8 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -208,9 +208,16 @@ protected: if (!state.mMatrix.isSimple()) return false; // check state/paint for transparency - if (state.mDrawModifiers.mShader || - state.mAlpha != 1.0f || - (mPaint && mPaint->getAlpha() != 0xFF)) return false; + if (mPaint) { + if (mPaint->getShader() && !mPaint->getShader()->isOpaque()) { + return false; + } + if (mPaint->getAlpha() != 0xFF) { + return false; + } + } + + if (state.mAlpha != 1.0f) return false; SkXfermode::Mode mode = OpenGLRenderer::getXfermodeDirect(mPaint); return (mode == SkXfermode::kSrcOver_Mode || @@ -592,37 +599,6 @@ private: const SkRegion* mRegion; }; -class ResetShaderOp : public StateOp { -public: - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { - renderer.resetShader(); - } - - virtual void output(int level, uint32_t logFlags) const { - OP_LOGS("ResetShader"); - } - - virtual const char* name() { return "ResetShader"; } -}; - -class SetupShaderOp : public StateOp { -public: - SetupShaderOp(SkiaShader* shader) - : mShader(shader) {} - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { - renderer.setupShader(mShader); - } - - virtual void output(int level, uint32_t logFlags) const { - OP_LOG("SetupShader, shader %p", mShader); - } - - virtual const char* name() { return "SetupShader"; } - -private: - SkiaShader* mShader; -}; - class ResetPaintFilterOp : public StateOp { public: virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 606c67e..229afdf 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -47,7 +47,6 @@ DisplayListRenderer::~DisplayListRenderer() { /////////////////////////////////////////////////////////////////////////////// DisplayListData* DisplayListRenderer::finishRecording() { - mShaderMap.clear(); mPaintMap.clear(); mRegionMap.clear(); mPathMap.clear(); @@ -394,15 +393,6 @@ status_t DisplayListRenderer::drawRects(const float* rects, int count, const SkP return DrawGlInfo::kStatusDone; } -void DisplayListRenderer::resetShader() { - addStateOp(new (alloc()) ResetShaderOp()); -} - -void DisplayListRenderer::setupShader(SkiaShader* shader) { - shader = refShader(shader); - addStateOp(new (alloc()) SetupShaderOp(shader)); -} - void DisplayListRenderer::resetPaintFilter() { addStateOp(new (alloc()) ResetPaintFilterOp()); } diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index d814111..f0ae00f 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -95,9 +95,6 @@ public: virtual bool clipRegion(const SkRegion* region, SkRegion::Op op); // Misc - should be implemented with SkPaint inspection - virtual void resetShader(); - virtual void setupShader(SkiaShader* shader); - virtual void resetPaintFilter(); virtual void setupPaintFilter(int clearBits, int setBits); @@ -269,21 +266,6 @@ private: return bitmap; } - inline SkiaShader* refShader(SkiaShader* shader) { - if (!shader) return NULL; - - SkiaShader* shaderCopy = mShaderMap.valueFor(shader); - // TODO: We also need to handle generation ID changes in compose shaders - if (shaderCopy == NULL || shaderCopy->getGenerationId() != shader->getGenerationId()) { - shaderCopy = shader->copy(); - // replaceValueFor() performs an add if the entry doesn't exist - mShaderMap.replaceValueFor(shader, shaderCopy); - mDisplayListData->shaders.add(shaderCopy); - mCaches.resourceCache.incrementRefcount(shaderCopy); - } - return shaderCopy; - } - inline const Res_png_9patch* refPatch(const Res_png_9patch* patch) { mDisplayListData->patchResources.add(patch); mCaches.resourceCache.incrementRefcount(patch); @@ -293,7 +275,6 @@ private: DefaultKeyedVector<const SkPaint*, const SkPaint*> mPaintMap; DefaultKeyedVector<const SkPath*, const SkPath*> mPathMap; DefaultKeyedVector<const SkRegion*, const SkRegion*> mRegionMap; - DefaultKeyedVector<SkiaShader*, SkiaShader*> mShaderMap; Caches& mCaches; DisplayListData* mDisplayListData; diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 647c281..4407ab0 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -73,7 +73,7 @@ status_t TextSetupFunctor::operator ()(int what, void* data) { } } renderer->setupDrawColorFilter(paint->getColorFilter()); - renderer->setupDrawShader(); + renderer->setupDrawShader(paint->getShader()); renderer->setupDrawBlending(paint); renderer->setupDrawProgram(); renderer->setupDrawModelView(kModelViewMode_Translate, false, @@ -85,7 +85,7 @@ status_t TextSetupFunctor::operator ()(int what, void* data) { renderer->setupDrawTexture(0); renderer->setupDrawPureColorUniforms(); renderer->setupDrawColorFilterUniforms(paint->getColorFilter()); - renderer->setupDrawShaderUniforms(pureTranslate); + renderer->setupDrawShaderUniforms(paint->getShader(), pureTranslate); renderer->setupDrawTextGammaUniforms(); return NO_ERROR; diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 691f1c9..71836dd 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -21,6 +21,7 @@ #include <sys/types.h> #include <SkCanvas.h> +#include <SkShader.h> #include <SkTypeface.h> #include <utils/Log.h> @@ -37,6 +38,7 @@ #include "PathTessellator.h" #include "Properties.h" #include "ShadowTessellator.h" +#include "SkiaShader.h" #include "utils/GLUtils.h" #include "Vector.h" #include "VertexBuffer.h" @@ -1053,6 +1055,45 @@ void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) #define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND) +// This class is purely for inspection. It inherits from SkShader, but Skia does not know how to +// use it. The OpenGLRenderer will look at it to find its Layer and whether it is opaque. +class LayerShader : public SkShader { +public: + LayerShader(Layer* layer, const SkMatrix* localMatrix) + : INHERITED(localMatrix) + , mLayer(layer) { + } + + virtual bool asACustomShader(void** data) const { + if (data) { + *data = static_cast<void*>(mLayer); + } + return true; + } + + virtual bool isOpaque() const { + return !mLayer->isBlend(); + } + +protected: + virtual void shadeSpan(int x, int y, SkPMColor[], int count) { + LOG_ALWAYS_FATAL("LayerShader should never be drawn with raster backend."); + } + + virtual void flatten(SkWriteBuffer&) const { + LOG_ALWAYS_FATAL("LayerShader should never be flattened."); + } + + virtual Factory getFactory() const { + LOG_ALWAYS_FATAL("LayerShader should never be created from a stream."); + return NULL; + } +private: + // Unowned. + Layer* mLayer; + typedef SkShader INHERITED; +}; + void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { if (CC_UNLIKELY(layer->region.isEmpty())) return; // nothing to draw @@ -1066,21 +1107,19 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { paint.setAntiAlias(true); paint.setColor(SkColorSetARGB(int(getLayerAlpha(layer) * 255), 0, 0, 0)); - SkiaShader* oldShader = mDrawModifiers.mShader; - // create LayerShader to map SaveLayer content into subsequent draw SkMatrix shaderMatrix; shaderMatrix.setTranslate(rect.left, rect.bottom); shaderMatrix.preScale(1, -1); - SkiaLayerShader layerShader(layer, &shaderMatrix); - mDrawModifiers.mShader = &layerShader; + LayerShader layerShader(layer, &shaderMatrix); + paint.setShader(&layerShader); // Since the drawing primitive is defined in local drawing space, // we don't need to modify the draw matrix const SkPath* maskPath = layer->getConvexMask(); DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint)); - mDrawModifiers.mShader = oldShader; + paint.setShader(NULL); restore(); return; @@ -1627,9 +1666,9 @@ void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) { mSetShaderColor = mDescription.setColorModulate(a); } -void OpenGLRenderer::setupDrawShader() { - if (mDrawModifiers.mShader) { - mDrawModifiers.mShader->describe(mDescription, mExtensions); +void OpenGLRenderer::setupDrawShader(const SkShader* shader) { + if (shader != NULL) { + SkiaShader::describe(&mCaches, mDescription, mExtensions, *shader); } } @@ -1655,15 +1694,21 @@ void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) { } } +static bool isBlendedColorFilter(const SkColorFilter* filter) { + if (filter == NULL) { + return false; + } + return (filter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) == 0; +} + void OpenGLRenderer::setupDrawBlending(const Layer* layer, bool swapSrcDst) { SkXfermode::Mode mode = layer->getMode(); // When the blending mode is kClear_Mode, we need to use a modulate color // argb=1,0,0,0 accountForClear(mode); + // TODO: check shader blending, once we have shader drawing support for layers. bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f || - (mColorSet && mColorA < 1.0f) || - (mDrawModifiers.mShader && mDrawModifiers.mShader->blend()) || - layer->getColorFilter(); + (mColorSet && mColorA < 1.0f) || isBlendedColorFilter(layer->getColorFilter()); chooseBlending(blend, mode, mDescription, swapSrcDst); } @@ -1673,8 +1718,8 @@ void OpenGLRenderer::setupDrawBlending(const SkPaint* paint, bool blend, bool sw // argb=1,0,0,0 accountForClear(mode); blend |= (mColorSet && mColorA < 1.0f) || - (mDrawModifiers.mShader && mDrawModifiers.mShader->blend()) || - (paint && paint->getColorFilter()); + (getShader(paint) && !getShader(paint)->isOpaque()) || + isBlendedColorFilter(getColorFilter(paint)); chooseBlending(blend, mode, mDescription, swapSrcDst); } @@ -1717,8 +1762,8 @@ void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset, } } -void OpenGLRenderer::setupDrawColorUniforms() { - if ((mColorSet && !mDrawModifiers.mShader) || (mDrawModifiers.mShader && mSetShaderColor)) { +void OpenGLRenderer::setupDrawColorUniforms(bool hasShader) { + if ((mColorSet && !hasShader) || (hasShader && mSetShaderColor)) { mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA); } } @@ -1729,20 +1774,22 @@ void OpenGLRenderer::setupDrawPureColorUniforms() { } } -void OpenGLRenderer::setupDrawShaderUniforms(bool ignoreTransform) { - if (mDrawModifiers.mShader) { - if (ignoreTransform) { - // if ignoreTransform=true was passed to setupDrawModelView, undo currentTransform() - // because it was built into modelView / the geometry, and the SkiaShader needs to - // compensate. - mat4 modelViewWithoutTransform; - modelViewWithoutTransform.loadInverse(*currentTransform()); - modelViewWithoutTransform.multiply(mModelViewMatrix); - mModelViewMatrix.load(modelViewWithoutTransform); - } - mDrawModifiers.mShader->setupProgram(mCaches.currentProgram, - mModelViewMatrix, *mSnapshot, &mTextureUnit); +void OpenGLRenderer::setupDrawShaderUniforms(const SkShader* shader, bool ignoreTransform) { + if (shader == NULL) { + return; + } + + if (ignoreTransform) { + // if ignoreTransform=true was passed to setupDrawModelView, undo currentTransform() + // because it was built into modelView / the geometry, and the description needs to + // compensate. + mat4 modelViewWithoutTransform; + modelViewWithoutTransform.loadInverse(*currentTransform()); + modelViewWithoutTransform.multiply(mModelViewMatrix); + mModelViewMatrix.load(modelViewWithoutTransform); } + + SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit, mExtensions, *shader); } void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) { @@ -2201,7 +2248,7 @@ status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, // Apply a scale transform on the canvas only when a shader is in use // Skia handles the ratio between the dst and src rects as a scale factor // when a shader is set - bool useScaleTransform = mDrawModifiers.mShader && scaled; + bool useScaleTransform = getShader(paint) && scaled; bool ignoreTransform = false; if (CC_LIKELY(currentTransform()->isPureTranslate() && !useScaleTransform)) { @@ -2359,13 +2406,13 @@ status_t OpenGLRenderer::drawVertexBuffer(VertexBufferMode mode, if (isAA) setupDrawAA(); setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha); setupDrawColorFilter(getColorFilter(paint)); - setupDrawShader(); + setupDrawShader(getShader(paint)); setupDrawBlending(paint, isAA); setupDrawProgram(); setupDrawModelView(kModelViewMode_Translate, useOffset, 0, 0, 0, 0); - setupDrawColorUniforms(); + setupDrawColorUniforms(getShader(paint)); setupDrawColorFilterUniforms(getColorFilter(paint)); - setupDrawShaderUniforms(); + setupDrawShaderUniforms(getShader(paint)); const void* vertices = vertexBuffer.getBuffer(); bool force = mCaches.unbindMeshBuffer(); @@ -2670,7 +2717,7 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text, const float sy = y - shadow->top + textShadow.dy; const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * mSnapshot->alpha; - if (mDrawModifiers.mShader) { + if (getShader(paint)) { textShadow.color = SK_ColorWHITE; } @@ -2678,7 +2725,7 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text, setupDrawWithTexture(true); setupDrawAlpha8Color(textShadow.color, shadowAlpha < 255 ? shadowAlpha : alpha); setupDrawColorFilter(getColorFilter(paint)); - setupDrawShader(); + setupDrawShader(getShader(paint)); setupDrawBlending(paint, true); setupDrawProgram(); setupDrawModelView(kModelViewMode_TranslateAndScale, false, @@ -2686,7 +2733,7 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text, setupDrawTexture(shadow->id); setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(getColorFilter(paint)); - setupDrawShaderUniforms(); + setupDrawShaderUniforms(getShader(paint)); setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); @@ -3008,21 +3055,6 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) { } /////////////////////////////////////////////////////////////////////////////// -// Shaders -/////////////////////////////////////////////////////////////////////////////// - -void OpenGLRenderer::resetShader() { - mDrawModifiers.mShader = NULL; -} - -void OpenGLRenderer::setupShader(SkiaShader* shader) { - mDrawModifiers.mShader = shader; - if (mDrawModifiers.mShader) { - mDrawModifiers.mShader->setCaches(mCaches); - } -} - -/////////////////////////////////////////////////////////////////////////////// // Draw filters /////////////////////////////////////////////////////////////////////////////// @@ -3080,7 +3112,7 @@ void OpenGLRenderer::drawPathTexture(const PathTexture* texture, setupDrawWithTexture(true); setupDrawAlpha8Color(paint->getColor(), alpha); setupDrawColorFilter(getColorFilter(paint)); - setupDrawShader(); + setupDrawShader(getShader(paint)); setupDrawBlending(paint, true); setupDrawProgram(); setupDrawModelView(kModelViewMode_TranslateAndScale, false, @@ -3088,7 +3120,7 @@ void OpenGLRenderer::drawPathTexture(const PathTexture* texture, setupDrawTexture(texture->id); setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(getColorFilter(paint)); - setupDrawShaderUniforms(); + setupDrawShaderUniforms(getShader(paint)); setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); @@ -3254,7 +3286,7 @@ status_t OpenGLRenderer::drawColorRects(const float* rects, int count, const SkP int color = paint->getColor(); // If a shader is set, preserve only the alpha - if (mDrawModifiers.mShader) { + if (getShader(paint)) { color |= 0x00ffffff; } @@ -3290,15 +3322,15 @@ status_t OpenGLRenderer::drawColorRects(const float* rects, int count, const SkP setupDraw(); setupDrawNoTexture(); setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha); - setupDrawShader(); + setupDrawShader(getShader(paint)); setupDrawColorFilter(getColorFilter(paint)); setupDrawBlending(paint); setupDrawProgram(); setupDrawDirtyRegionsDisabled(); setupDrawModelView(kModelViewMode_Translate, false, 0.0f, 0.0f, 0.0f, 0.0f, ignoreTransform); - setupDrawColorUniforms(); - setupDrawShaderUniforms(); + setupDrawColorUniforms(getShader(paint)); + setupDrawShaderUniforms(getShader(paint)); setupDrawColorFilterUniforms(getColorFilter(paint)); if (dirty && hasLayer()) { @@ -3314,21 +3346,21 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot const SkPaint* paint, bool ignoreTransform) { int color = paint->getColor(); // If a shader is set, preserve only the alpha - if (mDrawModifiers.mShader) { + if (getShader(paint)) { color |= 0x00ffffff; } setupDraw(); setupDrawNoTexture(); setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha); - setupDrawShader(); + setupDrawShader(getShader(paint)); setupDrawColorFilter(getColorFilter(paint)); setupDrawBlending(paint); setupDrawProgram(); setupDrawModelView(kModelViewMode_TranslateAndScale, false, left, top, right, bottom, ignoreTransform); - setupDrawColorUniforms(); - setupDrawShaderUniforms(ignoreTransform); + setupDrawColorUniforms(getShader(paint)); + setupDrawShaderUniforms(getShader(paint), ignoreTransform); setupDrawColorFilterUniforms(getColorFilter(paint)); setupDrawSimpleMesh(); @@ -3441,7 +3473,7 @@ void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, f setupDrawAlpha8Color(color, alpha); } setupDrawColorFilter(getColorFilter(paint)); - setupDrawShader(); + setupDrawShader(getShader(paint)); setupDrawBlending(paint, true); setupDrawProgram(); if (!dirty) setupDrawDirtyRegionsDisabled(); @@ -3449,7 +3481,7 @@ void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, f setupDrawTexture(texture); setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(getColorFilter(paint)); - setupDrawShaderUniforms(ignoreTransform); + setupDrawShaderUniforms(getShader(paint), ignoreTransform); setupDrawMesh(vertices, texCoords); glDrawArrays(drawMode, 0, elementsCount); diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index c6d9071..fc27947 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -26,7 +26,6 @@ #include <SkMatrix.h> #include <SkPaint.h> #include <SkRegion.h> -#include <SkShader.h> #include <SkXfermode.h> #include <utils/Blur.h> @@ -45,13 +44,15 @@ #include "Program.h" #include "Rect.h" #include "Renderer.h" -#include "StatefulBaseRenderer.h" #include "Snapshot.h" +#include "StatefulBaseRenderer.h" #include "UvMapper.h" #include "Vertex.h" #include "Caches.h" #include "CanvasProperty.h" +class SkShader; + namespace android { namespace uirenderer { @@ -59,7 +60,6 @@ class DeferredDisplayState; class RenderNode; class TextSetupFunctor; class VertexBuffer; -class SkiaShader; struct DrawModifiers { DrawModifiers() { @@ -70,7 +70,6 @@ struct DrawModifiers { memset(this, 0, sizeof(DrawModifiers)); } - SkiaShader* mShader; float mOverrideLayerAlpha; // Draw filters @@ -217,9 +216,6 @@ public: status_t drawShadow(const mat4& casterTransformXY, const mat4& casterTransformZ, float casterAlpha, bool casterUnclipped, const SkPath* casterPerimeter); - virtual void resetShader(); - virtual void setupShader(SkiaShader* shader); - virtual void resetPaintFilter(); virtual void setupPaintFilter(int clearBits, int setBits); @@ -467,6 +463,14 @@ protected: } /** + * Safely retrieves the Shader from the given Paint. If the paint is + * null then null is returned. + */ + static inline const SkShader* getShader(const SkPaint* paint) { + return paint ? paint->getShader() : NULL; + } + + /** * Set to true to suppress error checks at the end of a frame. */ virtual bool suppressErrorChecks() const { @@ -838,7 +842,7 @@ private: void setupDrawColor(float r, float g, float b, float a); void setupDrawAlpha8Color(int color, int alpha); void setupDrawTextGamma(const SkPaint* paint); - void setupDrawShader(); + void setupDrawShader(const SkShader* shader); void setupDrawColorFilter(const SkColorFilter* filter); void setupDrawBlending(const Layer* layer, bool swapSrcDst = false); void setupDrawBlending(const SkPaint* paint, bool blend = true, bool swapSrcDst = false); @@ -862,9 +866,17 @@ private: */ void setupDrawModelView(ModelViewMode mode, bool offset, float left, float top, float right, float bottom, bool ignoreTransform = false); - void setupDrawColorUniforms(); + void setupDrawColorUniforms(bool hasShader); void setupDrawPureColorUniforms(); - void setupDrawShaderUniforms(bool ignoreTransform = false); + + /** + * Setup uniforms for the current shader. + * + * @param shader SkShader on the current paint. + * + * @param ignoreTransform Set to true to ignore the transform in shader. + */ + void setupDrawShaderUniforms(const SkShader* shader, bool ignoreTransform = false); void setupDrawColorFilterUniforms(const SkColorFilter* paint); void setupDrawSimpleMesh(); void setupDrawTexture(GLuint texture); diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h index e191a26..23cab0e 100644 --- a/libs/hwui/Renderer.h +++ b/libs/hwui/Renderer.h @@ -35,7 +35,6 @@ class RenderNode; class Layer; class Matrix4; class SkiaColorFilter; -class SkiaShader; class Patch; enum DrawOpMode { @@ -183,9 +182,6 @@ public: virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) = 0; // Misc - should be implemented with SkPaint inspection - virtual void resetShader() = 0; - virtual void setupShader(SkiaShader* shader) = 0; - virtual void resetPaintFilter() = 0; virtual void setupPaintFilter(int clearBits, int setBits) = 0; diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp index 13a3e8e..8b553d1 100644 --- a/libs/hwui/ResourceCache.cpp +++ b/libs/hwui/ResourceCache.cpp @@ -71,11 +71,6 @@ void ResourceCache::incrementRefcount(const SkPath* pathResource) { incrementRefcount((void*) pathResource, kPath); } -void ResourceCache::incrementRefcount(SkiaShader* shaderResource) { - SkSafeRef(shaderResource->getSkShader()); - incrementRefcount((void*) shaderResource, kShader); -} - void ResourceCache::incrementRefcount(const Res_png_9patch* patchResource) { incrementRefcount((void*) patchResource, kNinePatch); } @@ -104,11 +99,6 @@ void ResourceCache::incrementRefcountLocked(const SkPath* pathResource) { incrementRefcountLocked((void*) pathResource, kPath); } -void ResourceCache::incrementRefcountLocked(SkiaShader* shaderResource) { - SkSafeRef(shaderResource->getSkShader()); - incrementRefcountLocked((void*) shaderResource, kShader); -} - void ResourceCache::incrementRefcountLocked(const Res_png_9patch* patchResource) { incrementRefcountLocked((void*) patchResource, kNinePatch); } @@ -132,11 +122,6 @@ void ResourceCache::decrementRefcount(const SkPath* pathResource) { decrementRefcount((void*) pathResource); } -void ResourceCache::decrementRefcount(SkiaShader* shaderResource) { - SkSafeUnref(shaderResource->getSkShader()); - decrementRefcount((void*) shaderResource); -} - void ResourceCache::decrementRefcount(const Res_png_9patch* patchResource) { decrementRefcount((void*) patchResource); } @@ -168,11 +153,6 @@ void ResourceCache::decrementRefcountLocked(const SkPath* pathResource) { decrementRefcountLocked((void*) pathResource); } -void ResourceCache::decrementRefcountLocked(SkiaShader* shaderResource) { - SkSafeUnref(shaderResource->getSkShader()); - decrementRefcountLocked((void*) shaderResource); -} - void ResourceCache::decrementRefcountLocked(const Res_png_9patch* patchResource) { decrementRefcountLocked((void*) patchResource); } @@ -227,25 +207,6 @@ void ResourceCache::destructorLocked(const SkBitmap* resource) { } } -void ResourceCache::destructor(SkiaShader* resource) { - Mutex::Autolock _l(mLock); - destructorLocked(resource); -} - -void ResourceCache::destructorLocked(SkiaShader* resource) { - ssize_t index = mCache->indexOfKey(resource); - ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; - if (ref == NULL) { - // If we're not tracking this resource, just delete it - delete resource; - return; - } - ref->destroyed = true; - if (ref->refCount == 0) { - deleteResourceReferenceLocked(resource, ref); - } -} - void ResourceCache::destructor(Res_png_9patch* resource) { Mutex::Autolock _l(mLock); destructorLocked(resource); @@ -333,11 +294,6 @@ void ResourceCache::deleteResourceReferenceLocked(const void* resource, Resource } } break; - case kShader: { - SkiaShader* shader = (SkiaShader*) resource; - delete shader; - } - break; case kNinePatch: { if (Caches::hasInstance()) { Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource); diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h index 4097ba4..3864d4b 100644 --- a/libs/hwui/ResourceCache.h +++ b/libs/hwui/ResourceCache.h @@ -20,7 +20,6 @@ #include <cutils/compiler.h> #include <SkBitmap.h> -#include <SkiaShader.h> #include <utils/KeyedVector.h> @@ -36,7 +35,6 @@ namespace uirenderer { */ enum ResourceType { kBitmap, - kShader, kNinePatch, kPath, kLayer @@ -70,36 +68,30 @@ public: void incrementRefcount(const SkPath* resource); void incrementRefcount(const SkBitmap* resource); - void incrementRefcount(SkiaShader* resource); void incrementRefcount(const Res_png_9patch* resource); void incrementRefcount(Layer* resource); void incrementRefcountLocked(const SkPath* resource); void incrementRefcountLocked(const SkBitmap* resource); - void incrementRefcountLocked(SkiaShader* resource); void incrementRefcountLocked(const Res_png_9patch* resource); void incrementRefcountLocked(Layer* resource); void decrementRefcount(const SkBitmap* resource); void decrementRefcount(const SkPath* resource); - void decrementRefcount(SkiaShader* resource); void decrementRefcount(const Res_png_9patch* resource); void decrementRefcount(Layer* resource); void decrementRefcountLocked(const SkBitmap* resource); void decrementRefcountLocked(const SkPath* resource); - void decrementRefcountLocked(SkiaShader* resource); void decrementRefcountLocked(const Res_png_9patch* resource); void decrementRefcountLocked(Layer* resource); void destructor(SkPath* resource); void destructor(const SkBitmap* resource); - void destructor(SkiaShader* resource); void destructor(Res_png_9patch* resource); void destructorLocked(SkPath* resource); void destructorLocked(const SkBitmap* resource); - void destructorLocked(SkiaShader* resource); void destructorLocked(Res_png_9patch* resource); bool recycle(SkBitmap* resource); diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp index 6a4a0c8..c672bc4 100644 --- a/libs/hwui/SkiaShader.cpp +++ b/libs/hwui/SkiaShader.cpp @@ -21,9 +21,10 @@ #include <SkMatrix.h> #include "Caches.h" +#include "Layer.h" +#include "Matrix.h" #include "SkiaShader.h" #include "Texture.h" -#include "Matrix.h" namespace android { namespace uirenderer { @@ -54,89 +55,142 @@ static inline void bindUniformColor(int slot, uint32_t color) { a); } -/////////////////////////////////////////////////////////////////////////////// -// Base shader -/////////////////////////////////////////////////////////////////////////////// - -void SkiaShader::copyFrom(const SkiaShader& shader) { - mType = shader.mType; - mKey = shader.mKey; - mTileX = shader.mTileX; - mTileY = shader.mTileY; - mBlend = shader.mBlend; - mUnitMatrix = shader.mUnitMatrix; - mShaderMatrix = shader.mShaderMatrix; - mGenerationId = shader.mGenerationId; +static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, GLenum wrapT) { + caches->bindTexture(texture->id); + texture->setWrapST(wrapS, wrapT); } -SkiaShader::SkiaShader(): mCaches(NULL) { -} +/** + * Compute the matrix to transform to screen space. + * @param screenSpace Output param for the computed matrix. + * @param unitMatrix The unit matrix for gradient shaders, as returned by SkShader::asAGradient, + * or identity. + * @param localMatrix Local matrix, as returned by SkShader::getLocalMatrix(). + * @param modelViewMatrix Model view matrix, as supplied by the OpenGLRenderer. + */ +static void computeScreenSpaceMatrix(mat4& screenSpace, const SkMatrix& unitMatrix, + const SkMatrix& localMatrix, const mat4& modelViewMatrix) { + mat4 shaderMatrix; + // uses implicit construction + shaderMatrix.loadInverse(localMatrix); + // again, uses implicit construction + screenSpace.loadMultiply(unitMatrix, shaderMatrix); + screenSpace.multiply(modelViewMatrix); +} + +// Returns true if one is a bitmap and the other is a gradient +static bool bitmapAndGradient(SkiaShaderType type1, SkiaShaderType type2) { + return (type1 == kBitmap_SkiaShaderType && type2 == kGradient_SkiaShaderType) + || (type2 == kBitmap_SkiaShaderType && type1 == kGradient_SkiaShaderType); +} + +SkiaShaderType SkiaShader::getType(const SkShader& shader) { + // First check for a gradient shader. + switch (shader.asAGradient(NULL)) { + case SkShader::kNone_GradientType: + // Not a gradient shader. Fall through to check for other types. + break; + case SkShader::kLinear_GradientType: + case SkShader::kRadial_GradientType: + case SkShader::kSweep_GradientType: + return kGradient_SkiaShaderType; + default: + // This is a Skia gradient that has no SkiaShader equivalent. Return None to skip. + return kNone_SkiaShaderType; + } -SkiaShader::SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX, - SkShader::TileMode tileY, const SkMatrix* matrix, bool blend): - mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend), - mCaches(NULL) { - setMatrix(matrix); - mGenerationId = 0; -} + // The shader is not a gradient. Check for a bitmap shader. + if (shader.asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType) { + return kBitmap_SkiaShaderType; + } -SkiaShader::~SkiaShader() { -} + // Check for a ComposeShader. + SkShader::ComposeRec rec; + if (shader.asACompose(&rec)) { + const SkiaShaderType shaderAType = getType(*rec.fShaderA); + const SkiaShaderType shaderBType = getType(*rec.fShaderB); + + // Compose is only supported if one is a bitmap and the other is a + // gradient. Otherwise, return None to skip. + if (!bitmapAndGradient(shaderAType, shaderBType)) { + return kNone_SkiaShaderType; + } + return kCompose_SkiaShaderType; + } -void SkiaShader::describe(ProgramDescription& description, const Extensions& extensions) { -} + if (shader.asACustomShader(NULL)) { + return kLayer_SkiaShaderType; + } -void SkiaShader::setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, - GLuint* textureUnit) { + return kNone_SkiaShaderType; } -void SkiaShader::bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT) { - mCaches->bindTexture(texture->id); - texture->setWrapST(wrapS, wrapT); +typedef void (*describeProc)(Caches* caches, ProgramDescription& description, + const Extensions& extensions, const SkShader& shader); + +describeProc gDescribeProc[] = { + InvalidSkiaShader::describe, + SkiaBitmapShader::describe, + SkiaGradientShader::describe, + SkiaComposeShader::describe, + SkiaLayerShader::describe, +}; + +typedef void (*setupProgramProc)(Caches* caches, const mat4& modelViewMatrix, + GLuint* textureUnit, const Extensions& extensions, const SkShader& shader); + +setupProgramProc gSetupProgramProc[] = { + InvalidSkiaShader::setupProgram, + SkiaBitmapShader::setupProgram, + SkiaGradientShader::setupProgram, + SkiaComposeShader::setupProgram, + SkiaLayerShader::setupProgram, +}; + +void SkiaShader::describe(Caches* caches, ProgramDescription& description, + const Extensions& extensions, const SkShader& shader) { + gDescribeProc[getType(shader)](caches, description, extensions, shader); } -void SkiaShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) { - screenSpace.loadMultiply(mUnitMatrix, mShaderMatrix); - screenSpace.multiply(modelView); +void SkiaShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, + GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) { + + gSetupProgramProc[getType(shader)](caches, modelViewMatrix, textureUnit, extensions, shader); } /////////////////////////////////////////////////////////////////////////////// // Layer shader /////////////////////////////////////////////////////////////////////////////// -SkiaLayerShader::SkiaLayerShader(Layer* layer, const SkMatrix* matrix): - SkiaShader(kBitmap, NULL, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, - matrix, layer->isBlend()), mLayer(layer) { - updateLocalMatrix(matrix); -} - -SkiaShader* SkiaLayerShader::copy() { - SkiaLayerShader* copy = new SkiaLayerShader(); - copy->copyFrom(*this); - copy->mLayer = mLayer; - return copy; -} - -void SkiaLayerShader::describe(ProgramDescription& description, const Extensions& extensions) { +void SkiaLayerShader::describe(Caches*, ProgramDescription& description, + const Extensions&, const SkShader& shader) { description.hasBitmap = true; } -void SkiaLayerShader::setupProgram(Program* program, const mat4& modelView, - const Snapshot& snapshot, GLuint* textureUnit) { +void SkiaLayerShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, + GLuint* textureUnit, const Extensions&, const SkShader& shader) { + Layer* layer; + if (!shader.asACustomShader(reinterpret_cast<void**>(&layer))) { + LOG_ALWAYS_FATAL("SkiaLayerShader::setupProgram called on the wrong type of shader!"); + } + GLuint textureSlot = (*textureUnit)++; - Caches::getInstance().activeTexture(textureSlot); + caches->activeTexture(textureSlot); - const float width = mLayer->getWidth(); - const float height = mLayer->getHeight(); + const float width = layer->getWidth(); + const float height = layer->getHeight(); mat4 textureTransform; - computeScreenSpaceMatrix(textureTransform, modelView); + computeScreenSpaceMatrix(textureTransform, SkMatrix::I(), shader.getLocalMatrix(), + modelViewMatrix); + // Uniforms - mLayer->bindTexture(); - mLayer->setWrap(GL_CLAMP_TO_EDGE); - mLayer->setFilter(GL_LINEAR); + layer->bindTexture(); + layer->setWrap(GL_CLAMP_TO_EDGE); + layer->setFilter(GL_LINEAR); + Program* program = caches->currentProgram; glUniform1i(program->getUniform("bitmapSampler"), textureSlot); glUniformMatrix4fv(program->getUniform("textureTransform"), 1, GL_FALSE, &textureTransform.data[0]); @@ -147,67 +201,99 @@ void SkiaLayerShader::setupProgram(Program* program, const mat4& modelView, // Bitmap shader /////////////////////////////////////////////////////////////////////////////// -SkiaBitmapShader::SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX, - SkShader::TileMode tileY, SkMatrix* matrix, bool blend): - SkiaShader(kBitmap, key, tileX, tileY, matrix, blend), mBitmap(bitmap), mTexture(NULL) { - updateLocalMatrix(matrix); -} - -SkiaShader* SkiaBitmapShader::copy() { - SkiaBitmapShader* copy = new SkiaBitmapShader(); - copy->copyFrom(*this); - copy->mBitmap = mBitmap; - return copy; -} +struct BitmapShaderInfo { + float width; + float height; + GLenum wrapS; + GLenum wrapT; + Texture* texture; +}; -void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) { - Texture* texture = mCaches->textureCache.get(mBitmap); - if (!texture) return; - mTexture = texture; +static bool bitmapShaderHelper(Caches* caches, ProgramDescription* description, + BitmapShaderInfo* shaderInfo, + const Extensions& extensions, + const SkBitmap& bitmap, SkShader::TileMode tileModes[2]) { + Texture* texture = caches->textureCache.get(&bitmap); + if (!texture) return false; const float width = texture->width; const float height = texture->height; + GLenum wrapS, wrapT; - description.hasBitmap = true; + if (description) { + description->hasBitmap = true; + } // The driver does not support non-power of two mirrored/repeated // textures, so do it ourselves if (!extensions.hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) && - (mTileX != SkShader::kClamp_TileMode || mTileY != SkShader::kClamp_TileMode)) { - description.isBitmapNpot = true; - description.bitmapWrapS = gTileModes[mTileX]; - description.bitmapWrapT = gTileModes[mTileY]; - mWrapS = GL_CLAMP_TO_EDGE; - mWrapT = GL_CLAMP_TO_EDGE; + (tileModes[0] != SkShader::kClamp_TileMode || + tileModes[1] != SkShader::kClamp_TileMode)) { + if (description) { + description->isBitmapNpot = true; + description->bitmapWrapS = gTileModes[tileModes[0]]; + description->bitmapWrapT = gTileModes[tileModes[1]]; + } + wrapS = GL_CLAMP_TO_EDGE; + wrapT = GL_CLAMP_TO_EDGE; } else { - mWrapS = gTileModes[mTileX]; - mWrapT = gTileModes[mTileY]; + wrapS = gTileModes[tileModes[0]]; + wrapT = gTileModes[tileModes[1]]; + } + + if (shaderInfo) { + shaderInfo->width = width; + shaderInfo->height = height; + shaderInfo->wrapS = wrapS; + shaderInfo->wrapT = wrapT; + shaderInfo->texture = texture; } + return true; } -void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView, - const Snapshot&, GLuint* textureUnit) { +void SkiaBitmapShader::describe(Caches* caches, ProgramDescription& description, + const Extensions& extensions, const SkShader& shader) { + SkBitmap bitmap; + SkShader::TileMode xy[2]; + if (shader.asABitmap(&bitmap, NULL, xy) != SkShader::kDefault_BitmapType) { + LOG_ALWAYS_FATAL("SkiaBitmapShader::describe called with a different kind of shader!"); + } + bitmapShaderHelper(caches, &description, NULL, extensions, bitmap, xy); +} + +void SkiaBitmapShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, + GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) { + SkBitmap bitmap; + SkShader::TileMode xy[2]; + if (shader.asABitmap(&bitmap, NULL, xy) != SkShader::kDefault_BitmapType) { + LOG_ALWAYS_FATAL("SkiaBitmapShader::setupProgram called with a different kind of shader!"); + } + GLuint textureSlot = (*textureUnit)++; Caches::getInstance().activeTexture(textureSlot); - Texture* texture = mTexture; - mTexture = NULL; - if (!texture) return; - const AutoTexture autoCleanup(texture); + BitmapShaderInfo shaderInfo; + if (!bitmapShaderHelper(caches, NULL, &shaderInfo, extensions, bitmap, xy)) { + return; + } - const float width = texture->width; - const float height = texture->height; + Program* program = caches->currentProgram; + Texture* texture = shaderInfo.texture; + + const AutoTexture autoCleanup(texture); mat4 textureTransform; - computeScreenSpaceMatrix(textureTransform, modelView); + computeScreenSpaceMatrix(textureTransform, SkMatrix::I(), shader.getLocalMatrix(), + modelViewMatrix); // Uniforms - bindTexture(texture, mWrapS, mWrapT); + bindTexture(caches, texture, shaderInfo.wrapS, shaderInfo.wrapT); texture->setFilter(GL_LINEAR); glUniform1i(program->getUniform("bitmapSampler"), textureSlot); glUniformMatrix4fv(program->getUniform("textureTransform"), 1, GL_FALSE, &textureTransform.data[0]); - glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height); + glUniform2f(program->getUniform("textureDimension"), 1.0f / shaderInfo.width, + 1.0f / shaderInfo.height); } /////////////////////////////////////////////////////////////////////////////// @@ -225,74 +311,6 @@ static void toUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) { matrix->postScale(inv, inv); } -SkiaLinearGradientShader::SkiaLinearGradientShader(float* bounds, uint32_t* colors, - float* positions, int count, SkShader* key, SkShader::TileMode tileMode, - SkMatrix* matrix, bool blend): - SkiaShader(kLinearGradient, key, tileMode, tileMode, matrix, blend), - mBounds(bounds), mColors(colors), mPositions(positions), mCount(count) { - SkPoint points[2]; - points[0].set(bounds[0], bounds[1]); - points[1].set(bounds[2], bounds[3]); - - SkMatrix unitMatrix; - toUnitMatrix(points, &unitMatrix); - mUnitMatrix.load(unitMatrix); - - updateLocalMatrix(matrix); - - mIsSimple = count == 2 && tileMode == SkShader::kClamp_TileMode; -} - -SkiaLinearGradientShader::~SkiaLinearGradientShader() { - delete[] mBounds; - delete[] mColors; - delete[] mPositions; -} - -SkiaShader* SkiaLinearGradientShader::copy() { - SkiaLinearGradientShader* copy = new SkiaLinearGradientShader(); - copy->copyFrom(*this); - copy->mBounds = new float[4]; - memcpy(copy->mBounds, mBounds, sizeof(float) * 4); - copy->mColors = new uint32_t[mCount]; - memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount); - copy->mPositions = new float[mCount]; - memcpy(copy->mPositions, mPositions, sizeof(float) * mCount); - copy->mCount = mCount; - copy->mIsSimple = mIsSimple; - return copy; -} - -void SkiaLinearGradientShader::describe(ProgramDescription& description, - const Extensions& extensions) { - description.hasGradient = true; - description.gradientType = ProgramDescription::kGradientLinear; - description.isSimpleGradient = mIsSimple; -} - -void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelView, - const Snapshot&, GLuint* textureUnit) { - if (CC_UNLIKELY(!mIsSimple)) { - GLuint textureSlot = (*textureUnit)++; - Caches::getInstance().activeTexture(textureSlot); - - Texture* texture = mCaches->gradientCache.get(mColors, mPositions, mCount); - - // Uniforms - bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]); - glUniform1i(program->getUniform("gradientSampler"), textureSlot); - } else { - bindUniformColor(program->getUniform("startColor"), mColors[0]); - bindUniformColor(program->getUniform("endColor"), mColors[1]); - } - - Caches::getInstance().dither.setupProgram(program, textureUnit); - - mat4 screenSpace; - computeScreenSpaceMatrix(screenSpace, modelView); - glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); -} - /////////////////////////////////////////////////////////////////////////////// // Circular gradient shader /////////////////////////////////////////////////////////////////////////////// @@ -304,37 +322,6 @@ static void toCircularUnitMatrix(const float x, const float y, const float radiu matrix->postScale(inv, inv); } -SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float radius, - uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode, - SkMatrix* matrix, bool blend): - SkiaSweepGradientShader(kCircularGradient, colors, positions, count, key, - tileMode, matrix, blend) { - SkMatrix unitMatrix; - toCircularUnitMatrix(x, y, radius, &unitMatrix); - mUnitMatrix.load(unitMatrix); - - updateLocalMatrix(matrix); -} - -SkiaShader* SkiaCircularGradientShader::copy() { - SkiaCircularGradientShader* copy = new SkiaCircularGradientShader(); - copy->copyFrom(*this); - copy->mColors = new uint32_t[mCount]; - memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount); - copy->mPositions = new float[mCount]; - memcpy(copy->mPositions, mPositions, sizeof(float) * mCount); - copy->mCount = mCount; - copy->mIsSimple = mIsSimple; - return copy; -} - -void SkiaCircularGradientShader::describe(ProgramDescription& description, - const Extensions& extensions) { - description.hasGradient = true; - description.gradientType = ProgramDescription::kGradientCircular; - description.isSimpleGradient = mIsSimple; -} - /////////////////////////////////////////////////////////////////////////////// // Sweep gradient shader /////////////////////////////////////////////////////////////////////////////// @@ -343,74 +330,103 @@ static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) { matrix->setTranslate(-x, -y); } -SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* colors, - float* positions, int count, SkShader* key, SkMatrix* matrix, bool blend): - SkiaShader(kSweepGradient, key, SkShader::kClamp_TileMode, - SkShader::kClamp_TileMode, matrix, blend), - mColors(colors), mPositions(positions), mCount(count) { - SkMatrix unitMatrix; - toSweepUnitMatrix(x, y, &unitMatrix); - mUnitMatrix.load(unitMatrix); - - updateLocalMatrix(matrix); - - mIsSimple = count == 2; -} - -SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, uint32_t* colors, - float* positions, int count, SkShader* key, SkShader::TileMode tileMode, - SkMatrix* matrix, bool blend): - SkiaShader(type, key, tileMode, tileMode, matrix, blend), - mColors(colors), mPositions(positions), mCount(count) { - // protected method, that doesn't setup mUnitMatrix - should be handled by subclass - - mIsSimple = count == 2 && tileMode == SkShader::kClamp_TileMode; -} - -SkiaSweepGradientShader::~SkiaSweepGradientShader() { - delete[] mColors; - delete[] mPositions; -} - -SkiaShader* SkiaSweepGradientShader::copy() { - SkiaSweepGradientShader* copy = new SkiaSweepGradientShader(); - copy->copyFrom(*this); - copy->mColors = new uint32_t[mCount]; - memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount); - copy->mPositions = new float[mCount]; - memcpy(copy->mPositions, mPositions, sizeof(float) * mCount); - copy->mCount = mCount; - copy->mIsSimple = mIsSimple; - return copy; -} +/////////////////////////////////////////////////////////////////////////////// +// Common gradient code +/////////////////////////////////////////////////////////////////////////////// -void SkiaSweepGradientShader::describe(ProgramDescription& description, - const Extensions& extensions) { +static bool isSimpleGradient(const SkShader::GradientInfo& gradInfo) { + return gradInfo.fColorCount == 2 && gradInfo.fTileMode == SkShader::kClamp_TileMode; +} + +void SkiaGradientShader::describe(Caches*, ProgramDescription& description, + const Extensions& extensions, const SkShader& shader) { + SkShader::GradientInfo gradInfo; + gradInfo.fColorCount = 0; + gradInfo.fColors = NULL; + gradInfo.fColorOffsets = NULL; + + switch (shader.asAGradient(&gradInfo)) { + case SkShader::kLinear_GradientType: + description.gradientType = ProgramDescription::kGradientLinear; + break; + case SkShader::kRadial_GradientType: + description.gradientType = ProgramDescription::kGradientCircular; + break; + case SkShader::kSweep_GradientType: + description.gradientType = ProgramDescription::kGradientSweep; + break; + default: + // Do nothing. This shader is unsupported. + return; + } description.hasGradient = true; - description.gradientType = ProgramDescription::kGradientSweep; - description.isSimpleGradient = mIsSimple; -} - -void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelView, - const Snapshot& snapshot, GLuint* textureUnit) { - if (CC_UNLIKELY(!mIsSimple)) { + description.isSimpleGradient = isSimpleGradient(gradInfo); +} + +void SkiaGradientShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, + GLuint* textureUnit, const Extensions&, const SkShader& shader) { + // SkShader::GradientInfo.fColorCount is an in/out parameter. As input, it tells asAGradient + // how much space has been allocated for fColors and fColorOffsets. 10 was chosen + // arbitrarily, but should be >= 2. + // As output, it tells the number of actual colors/offsets in the gradient. + const int COLOR_COUNT = 10; + SkAutoSTMalloc<COLOR_COUNT, SkColor> colorStorage(COLOR_COUNT); + SkAutoSTMalloc<COLOR_COUNT, SkScalar> positionStorage(COLOR_COUNT); + + SkShader::GradientInfo gradInfo; + gradInfo.fColorCount = COLOR_COUNT; + gradInfo.fColors = colorStorage.get(); + gradInfo.fColorOffsets = positionStorage.get(); + + SkShader::GradientType gradType = shader.asAGradient(&gradInfo); + + Program* program = caches->currentProgram; + if (CC_UNLIKELY(!isSimpleGradient(gradInfo))) { + if (gradInfo.fColorCount > COLOR_COUNT) { + // There was not enough room in our arrays for all the colors and offsets. Try again, + // now that we know the true number of colors. + gradInfo.fColors = colorStorage.reset(gradInfo.fColorCount); + gradInfo.fColorOffsets = positionStorage.reset(gradInfo.fColorCount); + + shader.asAGradient(&gradInfo); + } GLuint textureSlot = (*textureUnit)++; - Caches::getInstance().activeTexture(textureSlot); + caches->activeTexture(textureSlot); - Texture* texture = mCaches->gradientCache.get(mColors, mPositions, mCount); +#ifndef SK_SCALAR_IS_FLOAT + #error Need to convert gradInfo.fColorOffsets to float! +#endif + Texture* texture = caches->gradientCache.get(gradInfo.fColors, gradInfo.fColorOffsets, + gradInfo.fColorCount); // Uniforms - bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]); + bindTexture(caches, texture, gTileModes[gradInfo.fTileMode], gTileModes[gradInfo.fTileMode]); glUniform1i(program->getUniform("gradientSampler"), textureSlot); } else { - bindUniformColor(program->getUniform("startColor"), mColors[0]); - bindUniformColor(program->getUniform("endColor"), mColors[1]); + bindUniformColor(program->getUniform("startColor"), gradInfo.fColors[0]); + bindUniformColor(program->getUniform("endColor"), gradInfo.fColors[1]); } - mCaches->dither.setupProgram(program, textureUnit); + caches->dither.setupProgram(program, textureUnit); + + SkMatrix unitMatrix; + switch (gradType) { + case SkShader::kLinear_GradientType: + toUnitMatrix(gradInfo.fPoint, &unitMatrix); + break; + case SkShader::kRadial_GradientType: + toCircularUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, + gradInfo.fRadius[0], &unitMatrix); + break; + case SkShader::kSweep_GradientType: + toSweepUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, &unitMatrix); + break; + default: + LOG_ALWAYS_FATAL("Invalid SkShader gradient type %d", gradType); + } mat4 screenSpace; - computeScreenSpaceMatrix(screenSpace, modelView); + computeScreenSpaceMatrix(screenSpace, unitMatrix, shader.getLocalMatrix(), modelViewMatrix); glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); } @@ -418,49 +434,39 @@ void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelVi // Compose shader /////////////////////////////////////////////////////////////////////////////// -SkiaComposeShader::SkiaComposeShader(SkiaShader* first, SkiaShader* second, - SkXfermode::Mode mode, SkShader* key): - SkiaShader(kCompose, key, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, - NULL, first->blend() || second->blend()), - mFirst(first), mSecond(second), mMode(mode), mCleanup(false) { -} - -SkiaComposeShader::~SkiaComposeShader() { - if (mCleanup) { - delete mFirst; - delete mSecond; +void SkiaComposeShader::describe(Caches* caches, ProgramDescription& description, + const Extensions& extensions, const SkShader& shader) { + SkShader::ComposeRec rec; + if (!shader.asACompose(&rec)) { + LOG_ALWAYS_FATAL("SkiaComposeShader::describe called on the wrong shader type!"); } -} - -SkiaShader* SkiaComposeShader::copy() { - SkiaComposeShader* copy = new SkiaComposeShader(); - copy->copyFrom(*this); - copy->mFirst = mFirst->copy(); - copy->mSecond = mSecond->copy(); - copy->mMode = mMode; - copy->cleanup(); - return copy; -} - -void SkiaComposeShader::describe(ProgramDescription& description, const Extensions& extensions) { - mFirst->describe(description, extensions); - mSecond->describe(description, extensions); - if (mFirst->type() == kBitmap) { + SkiaShader::describe(caches, description, extensions, *rec.fShaderA); + SkiaShader::describe(caches, description, extensions, *rec.fShaderB); + if (SkiaShader::getType(*rec.fShaderA) == kBitmap_SkiaShaderType) { description.isBitmapFirst = true; } - description.shadersMode = mMode; + if (!SkXfermode::AsMode(rec.fMode, &description.shadersMode)) { + // TODO: Support other modes. + description.shadersMode = SkXfermode::kSrcOver_Mode; + } } -void SkiaComposeShader::setupProgram(Program* program, const mat4& modelView, - const Snapshot& snapshot, GLuint* textureUnit) { +void SkiaComposeShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, + GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) { + SkShader::ComposeRec rec; + if (!shader.asACompose(&rec)) { + LOG_ALWAYS_FATAL("SkiaComposeShader::setupProgram called on the wrong shader type!"); + } + // Apply this compose shader's local transform and pass it down to // the child shaders. They will in turn apply their local transform // to this matrix. mat4 transform; - computeScreenSpaceMatrix(transform, modelView); + computeScreenSpaceMatrix(transform, SkMatrix::I(), shader.getLocalMatrix(), + modelViewMatrix); - mFirst->setupProgram(program, transform, snapshot, textureUnit); - mSecond->setupProgram(program, transform, snapshot, textureUnit); + SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderA); + SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderB); } }; // namespace uirenderer diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h index 9f30257..034c3f6 100644 --- a/libs/hwui/SkiaShader.h +++ b/libs/hwui/SkiaShader.h @@ -28,249 +28,90 @@ #include "ProgramCache.h" #include "TextureCache.h" #include "GradientCache.h" -#include "Snapshot.h" namespace android { namespace uirenderer { class Caches; - -/////////////////////////////////////////////////////////////////////////////// -// Base shader -/////////////////////////////////////////////////////////////////////////////// +class Layer; /** - * Represents a Skia shader. A shader will modify the GL context and active - * program to recreate the original effect. + * Type of Skia shader in use. */ +enum SkiaShaderType { + kNone_SkiaShaderType, + kBitmap_SkiaShaderType, + kGradient_SkiaShaderType, + kCompose_SkiaShaderType, + kLayer_SkiaShaderType +}; + class SkiaShader { public: - /** - * Type of Skia shader in use. - */ - enum Type { - kNone, - kBitmap, - kLinearGradient, - kCircularGradient, - kSweepGradient, - kCompose - }; - - ANDROID_API SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX, - SkShader::TileMode tileY, const SkMatrix* matrix, bool blend); - virtual ~SkiaShader(); - - virtual SkiaShader* copy() = 0; - void copyFrom(const SkiaShader& shader); - - virtual void describe(ProgramDescription& description, const Extensions& extensions); - virtual void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, - GLuint* textureUnit); - - inline SkShader* getSkShader() { - return mKey; - } - - inline bool blend() const { - return mBlend; - } - - Type type() const { - return mType; - } - - virtual void setCaches(Caches& caches) { - mCaches = &caches; - } - - uint32_t getGenerationId() { - return mGenerationId; - } - - void setMatrix(const SkMatrix* matrix) { - updateLocalMatrix(matrix); - mGenerationId++; + static SkiaShaderType getType(const SkShader& shader); + static void describe(Caches* caches, ProgramDescription& description, + const Extensions& extensions, const SkShader& shader); + static void setupProgram(Caches* caches, const mat4& modelViewMatrix, + GLuint* textureUnit, const Extensions& extensions, const SkShader& shader); +}; + +class InvalidSkiaShader { +public: + static void describe(Caches* caches, ProgramDescription& description, + const Extensions& extensions, const SkShader& shader) { + // This shader is unsupported. Skip it. } - - void updateLocalMatrix(const SkMatrix* matrix) { - if (matrix) { - mat4 localMatrix(*matrix); - mShaderMatrix.loadInverse(localMatrix); - } else { - mShaderMatrix.loadIdentity(); - } + static void setupProgram(Caches* caches, const mat4& modelViewMatrix, + GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) { + // This shader is unsupported. Skip it. } - void computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView); - -protected: - SkiaShader(); - - /** - * The appropriate texture unit must have been activated prior to invoking - * this method. - */ - inline void bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT); - - Type mType; - SkShader* mKey; - SkShader::TileMode mTileX; - SkShader::TileMode mTileY; - bool mBlend; - - Caches* mCaches; - - mat4 mUnitMatrix; - mat4 mShaderMatrix; - -private: - uint32_t mGenerationId; -}; // struct SkiaShader - - -/////////////////////////////////////////////////////////////////////////////// -// Implementations -/////////////////////////////////////////////////////////////////////////////// - +}; /** * A shader that draws a layer. */ -struct SkiaLayerShader: public SkiaShader { - SkiaLayerShader(Layer* layer, const SkMatrix* matrix); - SkiaShader* copy(); - - void describe(ProgramDescription& description, const Extensions& extensions); - void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, - GLuint* textureUnit); - -private: - SkiaLayerShader() { - } - - Layer* mLayer; -}; // struct SkiaLayerShader +class SkiaLayerShader { +public: + static void describe(Caches* caches, ProgramDescription& description, + const Extensions& extensions, const SkShader& shader); + static void setupProgram(Caches* caches, const mat4& modelViewMatrix, + GLuint* textureUnit, const Extensions& extensions, const SkShader& shader); +}; // class SkiaLayerShader /** * A shader that draws a bitmap. */ -struct SkiaBitmapShader: public SkiaShader { - ANDROID_API SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX, - SkShader::TileMode tileY, SkMatrix* matrix, bool blend); - SkiaShader* copy(); - - void describe(ProgramDescription& description, const Extensions& extensions); - void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, - GLuint* textureUnit); - -private: - SkiaBitmapShader() : mBitmap(NULL), mTexture(NULL) { - } - - SkBitmap* mBitmap; - Texture* mTexture; - GLenum mWrapS; - GLenum mWrapT; -}; // struct SkiaBitmapShader - -/** - * A shader that draws a linear gradient. - */ -struct SkiaLinearGradientShader: public SkiaShader { - ANDROID_API SkiaLinearGradientShader(float* bounds, uint32_t* colors, float* positions, - int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend); - ~SkiaLinearGradientShader(); - SkiaShader* copy(); - - void describe(ProgramDescription& description, const Extensions& extensions); - void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, - GLuint* textureUnit); +class SkiaBitmapShader { +public: + static void describe(Caches* caches, ProgramDescription& description, + const Extensions& extensions, const SkShader& shader); + static void setupProgram(Caches* caches, const mat4& modelViewMatrix, + GLuint* textureUnit, const Extensions& extensions, const SkShader& shader); -private: - SkiaLinearGradientShader() { - } - bool mIsSimple; - float* mBounds; - uint32_t* mColors; - float* mPositions; - int mCount; -}; // struct SkiaLinearGradientShader +}; // class SkiaBitmapShader /** - * A shader that draws a sweep gradient. + * A shader that draws one of three types of gradient, depending on shader param. */ -struct SkiaSweepGradientShader: public SkiaShader { - ANDROID_API SkiaSweepGradientShader(float x, float y, uint32_t* colors, float* positions, - int count, SkShader* key, SkMatrix* matrix, bool blend); - ~SkiaSweepGradientShader(); - SkiaShader* copy(); - - virtual void describe(ProgramDescription& description, const Extensions& extensions); - void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, - GLuint* textureUnit); - -protected: - SkiaSweepGradientShader(Type type, uint32_t* colors, float* positions, - int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend); - SkiaSweepGradientShader() { - } - - bool mIsSimple; - uint32_t* mColors; - float* mPositions; - int mCount; -}; // struct SkiaSweepGradientShader - -/** - * A shader that draws a circular gradient. - */ -struct SkiaCircularGradientShader: public SkiaSweepGradientShader { - ANDROID_API SkiaCircularGradientShader(float x, float y, float radius, uint32_t* colors, - float* positions, int count, SkShader* key,SkShader::TileMode tileMode, - SkMatrix* matrix, bool blend); - SkiaShader* copy(); - - void describe(ProgramDescription& description, const Extensions& extensions); - -private: - SkiaCircularGradientShader() { - } -}; // struct SkiaCircularGradientShader +class SkiaGradientShader { +public: + static void describe(Caches* caches, ProgramDescription& description, + const Extensions& extensions, const SkShader& shader); + static void setupProgram(Caches* caches, const mat4& modelViewMatrix, + GLuint* textureUnit, const Extensions& extensions, const SkShader& shader); +}; /** * A shader that draws two shaders, composited with an xfermode. */ -struct SkiaComposeShader: public SkiaShader { - ANDROID_API SkiaComposeShader(SkiaShader* first, SkiaShader* second, SkXfermode::Mode mode, - SkShader* key); - ~SkiaComposeShader(); - SkiaShader* copy(); - - void setCaches(Caches& caches) { - SkiaShader::setCaches(caches); - mFirst->setCaches(caches); - mSecond->setCaches(caches); - } - - void describe(ProgramDescription& description, const Extensions& extensions); - void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, - GLuint* textureUnit); - -private: - SkiaComposeShader(): mCleanup(false) { - } - - void cleanup() { - mCleanup = true; - } - - SkiaShader* mFirst; - SkiaShader* mSecond; - SkXfermode::Mode mMode; - - bool mCleanup; -}; // struct SkiaComposeShader +class SkiaComposeShader { +public: + static void describe(Caches* caches, ProgramDescription& description, + const Extensions& extensions, const SkShader& shader); + static void setupProgram(Caches* caches, const mat4& modelViewMatrix, + GLuint* textureUnit, const Extensions& extensions, const SkShader& shader); +}; // class SkiaComposeShader }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index 34e2265..60b4b96 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -34,7 +34,7 @@ namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// TextureCache::TextureCache(): - mCache(LruCache<const SkBitmap*, Texture*>::kUnlimitedCapacity), + mCache(LruCache<const SkPixelRef*, Texture*>::kUnlimitedCapacity), mSize(0), mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE)), mFlushRate(DEFAULT_TEXTURE_CACHE_FLUSH_RATE) { char property[PROPERTY_VALUE_MAX]; @@ -58,7 +58,7 @@ TextureCache::TextureCache(): } TextureCache::TextureCache(uint32_t maxByteSize): - mCache(LruCache<const SkBitmap*, Texture*>::kUnlimitedCapacity), + mCache(LruCache<const SkPixelRef*, Texture*>::kUnlimitedCapacity), mSize(0), mMaxSize(maxByteSize) { init(); } @@ -103,7 +103,7 @@ void TextureCache::setFlushRate(float flushRate) { // Callbacks /////////////////////////////////////////////////////////////////////////////// -void TextureCache::operator()(const SkBitmap*&, Texture*& texture) { +void TextureCache::operator()(const SkPixelRef*&, Texture*& texture) { // This will be called already locked if (texture) { mSize -= texture->bitmapSize; @@ -122,7 +122,7 @@ void TextureCache::operator()(const SkBitmap*&, Texture*& texture) { /////////////////////////////////////////////////////////////////////////////// void TextureCache::resetMarkInUse() { - LruCache<const SkBitmap*, Texture*>::Iterator iter(mCache); + LruCache<const SkPixelRef*, Texture*>::Iterator iter(mCache); while (iter.next()) { iter.value()->isInUse = false; } @@ -140,7 +140,7 @@ bool TextureCache::canMakeTextureFromBitmap(const SkBitmap* bitmap) { // Returns a prepared Texture* that either is already in the cache or can fit // in the cache (and is thus added to the cache) Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap) { - Texture* texture = mCache.get(bitmap); + Texture* texture = mCache.get(bitmap->pixelRef()); if (!texture) { if (!canMakeTextureFromBitmap(bitmap)) { @@ -170,7 +170,7 @@ Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap) { if (mDebugEnabled) { ALOGD("Texture created, size = %d", size); } - mCache.put(bitmap, texture); + mCache.put(bitmap->pixelRef(), texture); } } else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) { // Texture was in the cache but is dirty, re-upload @@ -218,7 +218,7 @@ Texture* TextureCache::getTransient(const SkBitmap* bitmap) { } void TextureCache::remove(const SkBitmap* bitmap) { - mCache.remove(bitmap); + mCache.remove(bitmap->pixelRef()); } void TextureCache::removeDeferred(const SkBitmap* bitmap) { @@ -231,7 +231,7 @@ void TextureCache::clearGarbage() { size_t count = mGarbage.size(); for (size_t i = 0; i < count; i++) { const SkBitmap* bitmap = mGarbage.itemAt(i); - mCache.remove(bitmap); + mCache.remove(bitmap->pixelRef()); delete bitmap; } mGarbage.clear(); diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h index 48a10c2..e5b5c1a 100644 --- a/libs/hwui/TextureCache.h +++ b/libs/hwui/TextureCache.h @@ -49,7 +49,7 @@ namespace uirenderer { * Any texture added to the cache causing the cache to grow beyond the maximum * allowed size will also cause the oldest texture to be kicked out. */ -class TextureCache: public OnEntryRemoved<const SkBitmap*, Texture*> { +class TextureCache: public OnEntryRemoved<const SkPixelRef*, Texture*> { public: TextureCache(); TextureCache(uint32_t maxByteSize); @@ -59,7 +59,7 @@ public: * Used as a callback when an entry is removed from the cache. * Do not invoke directly. */ - void operator()(const SkBitmap*& bitmap, Texture*& texture); + void operator()(const SkPixelRef*& pixelRef, Texture*& texture); /** * Resets all Textures to not be marked as in use @@ -147,7 +147,7 @@ private: void init(); - LruCache<const SkBitmap*, Texture*> mCache; + LruCache<const SkPixelRef*, Texture*> mCache; uint32_t mSize; uint32_t mMaxSize; diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h index d4a23b8..8355f83 100644 --- a/libs/hwui/TreeInfo.h +++ b/libs/hwui/TreeInfo.h @@ -52,6 +52,7 @@ struct TreeInfo { : hasFunctors(false) , hasAnimations(false) , requiresUiRedraw(false) + , canDrawThisFrame(true) {} bool hasFunctors; // This is only updated if evaluateAnimations is true @@ -60,6 +61,13 @@ struct TreeInfo { // animate itself, such as if hasFunctors is true // This is only set if hasAnimations is true bool requiresUiRedraw; + // This is set to true if draw() can be called this frame + // false means that we must delay until the next vsync pulse as frame + // production is outrunning consumption + // NOTE that if this is false CanvasContext will set either requiresUiRedraw + // *OR* will post itself for the next vsync automatically, use this + // only to avoid calling draw() + bool canDrawThisFrame; } out; // TODO: Damage calculations diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 839ef91..b6b3428 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -360,7 +360,9 @@ void CanvasContext::destroyCanvasAndSurface() { setSurface(NULL); } -void CanvasContext::setSurface(EGLNativeWindowType window) { +void CanvasContext::setSurface(ANativeWindow* window) { + mNativeWindow = window; + if (mEglSurface != EGL_NO_SURFACE) { mGlobalContext->destroySurface(mEglSurface); mEglSurface = EGL_NO_SURFACE; @@ -393,7 +395,7 @@ void CanvasContext::requireSurface() { makeCurrent(); } -bool CanvasContext::initialize(EGLNativeWindowType window) { +bool CanvasContext::initialize(ANativeWindow* window) { if (mCanvas) return false; setSurface(window); mCanvas = new OpenGLRenderer(); @@ -401,11 +403,11 @@ bool CanvasContext::initialize(EGLNativeWindowType window) { return true; } -void CanvasContext::updateSurface(EGLNativeWindowType window) { +void CanvasContext::updateSurface(ANativeWindow* window) { setSurface(window); } -void CanvasContext::pauseSurface(EGLNativeWindowType window) { +void CanvasContext::pauseSurface(ANativeWindow* window) { // TODO: For now we just need a fence, in the future suspend any animations // and such to prevent from trying to render into this surface } @@ -456,7 +458,15 @@ void CanvasContext::prepareTree(TreeInfo& info) { info.frameTimeMs = mRenderThread.timeLord().frameTimeMs(); mRootRenderNode->prepareTree(info); - if (info.out.hasAnimations) { + int runningBehind = 0; + // TODO: This query is moderately expensive, investigate adding some sort + // of fast-path based off when we last called eglSwapBuffers() as well as + // last vsync time. Or something. + mNativeWindow->query(mNativeWindow.get(), + NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind); + info.out.canDrawThisFrame = !runningBehind; + + if (info.out.hasAnimations || !info.out.canDrawThisFrame) { if (info.out.hasFunctors) { info.out.requiresUiRedraw = true; } else if (!info.out.requiresUiRedraw) { @@ -467,6 +477,11 @@ void CanvasContext::prepareTree(TreeInfo& info) { } } +void CanvasContext::notifyFramePending() { + ATRACE_CALL(); + mRenderThread.pushBackFrameCallback(this); +} + void CanvasContext::draw(Rect* dirty) { LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE, "drawDisplayList called on a context with no canvas or surface!"); @@ -515,7 +530,9 @@ void CanvasContext::doFrame() { info.prepareTextures = false; prepareTree(info); - draw(NULL); + if (info.out.canDrawThisFrame) { + draw(NULL); + } } void CanvasContext::invokeFunctor(Functor* functor) { diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 4232f27..a54b33e 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -48,9 +48,9 @@ public: CanvasContext(bool translucent, RenderNode* rootRenderNode); virtual ~CanvasContext(); - bool initialize(EGLNativeWindowType window); - void updateSurface(EGLNativeWindowType window); - void pauseSurface(EGLNativeWindowType window); + bool initialize(ANativeWindow* window); + void updateSurface(ANativeWindow* window); + void pauseSurface(ANativeWindow* window); void setup(int width, int height, const Vector3& lightCenter, float lightRadius); void setOpaque(bool opaque); void makeCurrent(); @@ -73,11 +73,15 @@ public: ANDROID_API static void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize); + void notifyFramePending(); + private: + friend class RegisterFrameCallbackTask; + void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info); void prepareTree(TreeInfo& info); - void setSurface(EGLNativeWindowType window); + void setSurface(ANativeWindow* window); void swapBuffers(); void requireSurface(); @@ -85,6 +89,7 @@ private: GlobalContext* mGlobalContext; RenderThread& mRenderThread; + sp<ANativeWindow> mNativeWindow; EGLSurface mEglSurface; bool mDirtyRegionsEnabled; diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 3b8786c..ee3e059 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -87,7 +87,13 @@ void DrawFrameTask::postAndWait() { void DrawFrameTask::run() { ATRACE_NAME("DrawFrame"); - bool canUnblockUiThread = syncFrameState(); + bool canUnblockUiThread; + bool canDrawThisFrame; + { + TreeInfo info; + canUnblockUiThread = syncFrameState(info); + canDrawThisFrame = info.out.canDrawThisFrame; + } // Grab a copy of everything we need Rect dirty(mDirty); @@ -98,7 +104,9 @@ void DrawFrameTask::run() { unblockUiThread(); } - context->draw(&dirty); + if (CC_LIKELY(canDrawThisFrame)) { + context->draw(&dirty); + } if (!canUnblockUiThread) { unblockUiThread(); @@ -111,12 +119,11 @@ static void initTreeInfo(TreeInfo& info) { info.evaluateAnimations = true; } -bool DrawFrameTask::syncFrameState() { +bool DrawFrameTask::syncFrameState(TreeInfo& info) { ATRACE_CALL(); mRenderThread->timeLord().vsyncReceived(mFrameTimeNanos); mContext->makeCurrent(); Caches::getInstance().textureCache.resetMarkInUse(); - TreeInfo info; initTreeInfo(info); mContext->prepareDraw(&mLayers, info); if (info.out.hasAnimations) { diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h index b9307e1..acbc02a 100644 --- a/libs/hwui/renderthread/DrawFrameTask.h +++ b/libs/hwui/renderthread/DrawFrameTask.h @@ -24,6 +24,7 @@ #include "RenderTask.h" #include "../Rect.h" +#include "../TreeInfo.h" namespace android { namespace uirenderer { @@ -65,7 +66,7 @@ public: private: void postAndWait(); - bool syncFrameState(); + bool syncFrameState(TreeInfo& info); void unblockUiThread(); Mutex mLock; diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index ef8e45b..2e103d8 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -112,7 +112,7 @@ bool RenderProxy::loadSystemProperties() { return (bool) postAndWait(task); } -CREATE_BRIDGE2(initialize, CanvasContext* context, EGLNativeWindowType window) { +CREATE_BRIDGE2(initialize, CanvasContext* context, ANativeWindow* window) { return (void*) args->context->initialize(args->window); } @@ -123,7 +123,7 @@ bool RenderProxy::initialize(const sp<ANativeWindow>& window) { return (bool) postAndWait(task); } -CREATE_BRIDGE2(updateSurface, CanvasContext* context, EGLNativeWindowType window) { +CREATE_BRIDGE2(updateSurface, CanvasContext* context, ANativeWindow* window) { args->context->updateSurface(args->window); return NULL; } @@ -135,7 +135,7 @@ void RenderProxy::updateSurface(const sp<ANativeWindow>& window) { postAndWait(task); } -CREATE_BRIDGE2(pauseSurface, CanvasContext* context, EGLNativeWindowType window) { +CREATE_BRIDGE2(pauseSurface, CanvasContext* context, ANativeWindow* window) { args->context->pauseSurface(args->window); return NULL; } @@ -292,6 +292,17 @@ void RenderProxy::fence() { postAndWait(task); } +CREATE_BRIDGE1(notifyFramePending, CanvasContext* context) { + args->context->notifyFramePending(); + return NULL; +} + +void RenderProxy::notifyFramePending() { + SETUP_TASK(notifyFramePending); + args->context = mContext; + mRenderThread.queueAtFront(task); +} + void RenderProxy::post(RenderTask* task) { mRenderThread.queue(task); } diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 4d3499e..8aeb264 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -82,6 +82,7 @@ public: ANDROID_API void destroyLayer(DeferredLayerUpdater* layer); ANDROID_API void fence(); + ANDROID_API void notifyFramePending(); private: RenderThread& mRenderThread; diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 35a3eab..4a4e254 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -37,7 +37,7 @@ namespace renderthread { static const size_t EVENT_BUFFER_SIZE = 100; // Slight delay to give the UI time to push us a new frame before we replay -static const int DISPATCH_FRAME_CALLBACKS_DELAY = 0; +static const int DISPATCH_FRAME_CALLBACKS_DELAY = 4; TaskQueue::TaskQueue() : mHead(0), mTail(0) {} @@ -91,6 +91,15 @@ void TaskQueue::queue(RenderTask* task) { } } +void TaskQueue::queueAtFront(RenderTask* task) { + if (mTail) { + task->mNext = mHead; + mHead = task; + } else { + mTail = mHead = task; + } +} + void TaskQueue::remove(RenderTask* task) { // TaskQueue is strict here to enforce that users are keeping track of // their RenderTasks due to how their memory is managed @@ -188,20 +197,22 @@ static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) { return latest; } -void RenderThread::drainDisplayEventQueue() { +void RenderThread::drainDisplayEventQueue(bool skipCallbacks) { + ATRACE_CALL(); nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver); if (vsyncEvent > 0) { mVsyncRequested = false; mTimeLord.vsyncReceived(vsyncEvent); - if (!mFrameCallbackTaskPending) { + if (!skipCallbacks && !mFrameCallbackTaskPending) { + ATRACE_NAME("queue mFrameCallbackTask"); mFrameCallbackTaskPending = true; - //queueDelayed(mFrameCallbackTask, DISPATCH_FRAME_CALLBACKS_DELAY); - queue(mFrameCallbackTask); + queueDelayed(mFrameCallbackTask, DISPATCH_FRAME_CALLBACKS_DELAY); } } } void RenderThread::dispatchFrameCallbacks() { + ATRACE_CALL(); mFrameCallbackTaskPending = false; std::set<IFrameCallback*> callbacks; @@ -212,6 +223,15 @@ void RenderThread::dispatchFrameCallbacks() { } } +void RenderThread::requestVsync() { + if (!mVsyncRequested) { + mVsyncRequested = true; + status_t status = mDisplayEventReceiver->requestNextVsync(); + LOG_ALWAYS_FATAL_IF(status != NO_ERROR, + "requestNextVsync failed with status: %d", status); + } +} + bool RenderThread::threadLoop() { initializeDisplayEventReceiver(); @@ -236,6 +256,14 @@ bool RenderThread::threadLoop() { timeoutMillis = 0; } } + + if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) { + drainDisplayEventQueue(true); + mFrameCallbacks.insert( + mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end()); + mPendingRegistrationFrameCallbacks.clear(); + requestVsync(); + } } return false; @@ -250,6 +278,12 @@ void RenderThread::queue(RenderTask* task) { } } +void RenderThread::queueAtFront(RenderTask* task) { + AutoMutex _lock(mLock); + mQueue.queueAtFront(task); + mLooper->wake(); +} + void RenderThread::queueDelayed(RenderTask* task, int delayMs) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); task->mRunAt = now + milliseconds_to_nanoseconds(delayMs); @@ -262,17 +296,18 @@ void RenderThread::remove(RenderTask* task) { } void RenderThread::postFrameCallback(IFrameCallback* callback) { - mFrameCallbacks.insert(callback); - if (!mVsyncRequested) { - mVsyncRequested = true; - status_t status = mDisplayEventReceiver->requestNextVsync(); - LOG_ALWAYS_FATAL_IF(status != NO_ERROR, - "requestNextVsync failed with status: %d", status); - } + mPendingRegistrationFrameCallbacks.insert(callback); } void RenderThread::removeFrameCallback(IFrameCallback* callback) { mFrameCallbacks.erase(callback); + mPendingRegistrationFrameCallbacks.erase(callback); +} + +void RenderThread::pushBackFrameCallback(IFrameCallback* callback) { + if (mFrameCallbacks.erase(callback)) { + mPendingRegistrationFrameCallbacks.insert(callback); + } } RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) { @@ -281,11 +316,13 @@ RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) { if (!next) { mNextWakeup = LLONG_MAX; } else { + mNextWakeup = next->mRunAt; // Most tasks won't be delayed, so avoid unnecessary systemTime() calls if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) { next = mQueue.next(); + } else { + next = 0; } - mNextWakeup = next->mRunAt; } if (nextWakeup) { *nextWakeup = mNextWakeup; diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index 215d294..4412584 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -44,6 +44,7 @@ public: RenderTask* next(); void queue(RenderTask* task); + void queueAtFront(RenderTask* task); RenderTask* peek(); void remove(RenderTask* task); @@ -66,12 +67,16 @@ public: // RenderThread takes complete ownership of tasks that are queued // and will delete them after they are run ANDROID_API void queue(RenderTask* task); + ANDROID_API void queueAtFront(RenderTask* task); void queueDelayed(RenderTask* task, int delayMs); void remove(RenderTask* task); // Mimics android.view.Choreographer void postFrameCallback(IFrameCallback* callback); void removeFrameCallback(IFrameCallback* callback); + // If the callback is currently registered, it will be pushed back until + // the next vsync. If it is not currently registered this does nothing. + void pushBackFrameCallback(IFrameCallback* callback); TimeLord& timeLord() { return mTimeLord; } @@ -87,8 +92,9 @@ private: void initializeDisplayEventReceiver(); static int displayEventReceiverCallback(int fd, int events, void* data); - void drainDisplayEventQueue(); + void drainDisplayEventQueue(bool skipCallbacks = false); void dispatchFrameCallbacks(); + void requestVsync(); // Returns the next task to be run. If this returns NULL nextWakeup is set // to the time to requery for the nextTask to run. mNextWakeup is also @@ -104,6 +110,11 @@ private: DisplayEventReceiver* mDisplayEventReceiver; bool mVsyncRequested; std::set<IFrameCallback*> mFrameCallbacks; + // We defer the actual registration of these callbacks until + // both mQueue *and* mDisplayEventReceiver have been drained off all + // immediate events. This makes sure that we catch the next vsync, not + // the previous one + std::set<IFrameCallback*> mPendingRegistrationFrameCallbacks; bool mFrameCallbackTaskPending; DispatchFrameCallbacks* mFrameCallbackTask; diff --git a/media/jni/Android.mk b/media/jni/Android.mk index d658654..90fe695 100644 --- a/media/jni/Android.mk +++ b/media/jni/Android.mk @@ -2,7 +2,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - android_media_DngCreator.cpp \ android_media_ImageReader.cpp \ android_media_MediaCrypto.cpp \ android_media_MediaCodec.cpp \ @@ -42,7 +41,6 @@ LOCAL_SHARED_LIBRARIES := \ libjhead \ libexif \ libstagefright_amrnb_common \ - libimg_utils \ LOCAL_REQUIRED_MODULES := \ libjhead_jni @@ -55,7 +53,6 @@ LOCAL_C_INCLUDES += \ external/tremor/Tremor \ frameworks/base/core/jni \ frameworks/av/media/libmedia \ - frameworks/av/media/img_utils/include \ frameworks/av/media/libstagefright \ frameworks/av/media/libstagefright/codecs/amrnb/enc/src \ frameworks/av/media/libstagefright/codecs/amrnb/common \ diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 9d03cc3..6f42057 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -884,7 +884,6 @@ static int register_android_media_MediaPlayer(JNIEnv *env) "android/media/MediaPlayer", gMethods, NELEM(gMethods)); } -extern int register_android_media_DngCreator(JNIEnv *env); extern int register_android_media_ImageReader(JNIEnv *env); extern int register_android_media_Crypto(JNIEnv *env); extern int register_android_media_Drm(JNIEnv *env); @@ -914,11 +913,6 @@ jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) } assert(env != NULL); - if (register_android_media_DngCreator(env) < 0) { - ALOGE("ERROR: ImageReader native registration failed"); - goto bail; - } - if (register_android_media_ImageReader(env) < 0) { ALOGE("ERROR: ImageReader native registration failed"); goto bail; diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java index a77b647..a3caba2 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java @@ -17,6 +17,7 @@ package com.android.mediaframeworktest.unit; import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; import android.util.Range; import android.util.Rational; import android.util.SizeF; @@ -26,6 +27,8 @@ import android.graphics.PointF; import android.graphics.Rect; import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraMetadata; +import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.util.Size; import android.hardware.camera2.impl.CameraMetadataNative; @@ -46,6 +49,7 @@ import static com.android.mediaframeworktest.unit.ByteArrayHelpers.*; import java.lang.reflect.Array; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.List; /** * <pre> @@ -56,6 +60,10 @@ import java.nio.ByteOrder; */ public class CameraMetadataTest extends junit.framework.TestCase { + private static final boolean VERBOSE = false; + private static final String TAG = "CameraMetadataTest"; + + CameraMetadataNative mMetadata; // Sections @@ -940,7 +948,7 @@ public class CameraMetadataTest extends junit.framework.TestCase { }; int availableFormatTag = CameraMetadataNative.getTag("android.scaler.availableFormats"); - Key<int[]> formatKey = CameraCharacteristics.SCALER_AVAILABLE_FORMATS; + Key<int[]> formatKey = CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(); validateArrayMetadataReadWriteOverride(formatKey, availableFormats, expectedIntValues, availableFormatTag); @@ -1046,7 +1054,7 @@ public class CameraMetadataTest extends junit.framework.TestCase { 0x20, 320, 240, INPUT, // RAW16 }; Key<StreamConfiguration[]> configKey = - CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS; + CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS.getNativeKey(); mMetadata.writeValues(configKey.getTag(), toByteArray(rawAvailableStreamConfigs)); @@ -1074,7 +1082,7 @@ public class CameraMetadataTest extends junit.framework.TestCase { 0x21, 1920, 1080, 33333338 // BLOB }; Key<StreamConfigurationDuration[]> durationKey = - CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS; + CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS.getNativeKey(); mMetadata.writeValues(durationKey.getTag(), toByteArray(rawAvailableMinDurations)); @@ -1100,7 +1108,7 @@ public class CameraMetadataTest extends junit.framework.TestCase { 0x21, 1920, 1080, 33333338 // BLOB }; Key<StreamConfigurationDuration[]> stallDurationKey = - CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS; + CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS.getNativeKey(); mMetadata.writeValues(stallDurationKey.getTag(), toByteArray(rawAvailableStallDurations)); @@ -1158,6 +1166,31 @@ public class CameraMetadataTest extends junit.framework.TestCase { } } + @SmallTest + public void testCaptureResult() { + mMetadata.set(CaptureRequest.CONTROL_AE_MODE, + CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH); + + if (VERBOSE) mMetadata.dumpToLog(); + + CaptureResult captureResult = new CaptureResult(mMetadata, /*sequenceId*/0); + + List<CaptureResult.Key<?>> allKeys = captureResult.getKeys(); + if (VERBOSE) Log.v(TAG, "testCaptureResult: key list size " + allKeys); + for (CaptureResult.Key<?> key : captureResult.getKeys()) { + if (VERBOSE) { + Log.v(TAG, + "testCaptureResult: key " + key + " value" + captureResult.get(key)); + } + } + + assertTrue(allKeys.size() >= 1); // FIXME: android.statistics.faces counts as a key + assertTrue(allKeys.contains(CaptureResult.CONTROL_AE_MODE)); + + assertEquals(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH, + (int)captureResult.get(CaptureResult.CONTROL_AE_MODE)); + } + private static void checkStreamConfigurationMapByFormatSize(StreamConfigurationMap configMap, int format, int width, int height, boolean output) { diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml index f79819f..112e371 100644 --- a/packages/Keyguard/res/layout/keyguard_status_view.xml +++ b/packages/Keyguard/res/layout/keyguard_status_view.xml @@ -39,13 +39,12 @@ android:id="@+id/clock_view" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center_horizontal|top" + android:layout_gravity="center_horizontal" android:textColor="@color/clock_white" android:singleLine="true" style="@style/widget_big_thin" android:format12Hour="@string/keyguard_widget_12_hours_format" android:format24Hour="@string/keyguard_widget_24_hours_format" - android:baselineAligned="true" android:layout_marginBottom="@dimen/bottom_text_spacing_digital" /> <include layout="@layout/keyguard_status_area" /> diff --git a/packages/Keyguard/res/values-sw600dp-land/dimens.xml b/packages/Keyguard/res/values-sw600dp-land/dimens.xml index 5615ff7..13a6f62 100644 --- a/packages/Keyguard/res/values-sw600dp-land/dimens.xml +++ b/packages/Keyguard/res/values-sw600dp-land/dimens.xml @@ -26,5 +26,4 @@ <!-- Overload default clock widget parameters --> <dimen name="widget_big_font_size">88dp</dimen> - <dimen name="bottom_text_spacing_digital">-24dp</dimen> </resources>
\ No newline at end of file diff --git a/packages/Keyguard/res/values-sw600dp/dimens.xml b/packages/Keyguard/res/values-sw600dp/dimens.xml index a5e93dc..b954792 100644 --- a/packages/Keyguard/res/values-sw600dp/dimens.xml +++ b/packages/Keyguard/res/values-sw600dp/dimens.xml @@ -65,7 +65,7 @@ <!-- Overload default clock widget parameters --> <dimen name="widget_big_font_size">96dp</dimen> <dimen name="widget_label_font_size">16sp</dimen> - <dimen name="bottom_text_spacing_digital">-24dp</dimen> + <dimen name="bottom_text_spacing_digital">-8dp</dimen> <!-- EmergencyCarrierArea overlap - amount to overlap the emergency button and carrier text. Should be 0 on devices with plenty of room (e.g. tablets) --> diff --git a/packages/Keyguard/res/values/dimens.xml b/packages/Keyguard/res/values/dimens.xml index 6224aed..3830df7 100644 --- a/packages/Keyguard/res/values/dimens.xml +++ b/packages/Keyguard/res/values/dimens.xml @@ -155,7 +155,7 @@ <dimen name="eca_overlap">-10dip</dimen> <!-- Default clock parameters --> - <dimen name="bottom_text_spacing_digital">-18dp</dimen> + <dimen name="bottom_text_spacing_digital">-6dp</dimen> <dimen name="label_font_size">14dp</dimen> <dimen name="widget_label_font_size">14sp</dimen> <dimen name="widget_big_font_size">68dp</dimen> diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml index d20b269..8cf07fa 100644 --- a/packages/Keyguard/res/values/strings.xml +++ b/packages/Keyguard/res/values/strings.xml @@ -97,9 +97,9 @@ <string name="keyguard_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string> <!-- Time format strings for fall-back clock widget --> - <string name="keyguard_widget_12_hours_format" translatable="false">h:mm</string> + <string name="keyguard_widget_12_hours_format" translatable="false">h\uee01mm</string> <!-- Time format strings for fall-back clock widget --> - <string name="keyguard_widget_24_hours_format" translatable="false">kk:mm</string> + <string name="keyguard_widget_24_hours_format" translatable="false">kk\uee01mm</string> <!-- Accessibility description sent when user changes the current lock screen widget. [CHAR_LIMIT=none] --> <string name="keyguard_accessibility_widget_changed">%1$s. Widget %2$d of %3$d.</string> diff --git a/packages/Keyguard/res/values/styles.xml b/packages/Keyguard/res/values/styles.xml index 5ab00d2..11142cf 100644 --- a/packages/Keyguard/res/values/styles.xml +++ b/packages/Keyguard/res/values/styles.xml @@ -59,8 +59,6 @@ <!-- Built-in clock widget stuff --> <style name="widget_label"> - <item name="android:textStyle">bold</item> - <item name="android:fontFamily">sans-serif-light</item> <item name="android:textSize">@dimen/widget_label_font_size</item> </style> <style name="big_thin"> diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java index 2685447..d2bf30c 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java @@ -112,7 +112,9 @@ public class KeyguardHostView extends KeyguardViewBase { } public interface OnDismissAction { - /* returns true if the dismiss should be deferred */ + /** + * @return true if the dismiss should be deferred + */ boolean onDismiss(); } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java index ae55c4a..bef94fa 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java @@ -95,6 +95,10 @@ public class KeyguardStatusView extends GridLayout { final boolean screenOn = KeyguardUpdateMonitor.getInstance(mContext).isScreenOn(); setEnableMarquee(screenOn); refresh(); + + // Disable elegant text height because our fancy colon makes the ymin value huge for no + // reason. + mClockView.setElegantTextHeight(false); } protected void refresh() { @@ -164,6 +168,10 @@ public class KeyguardStatusView extends GridLayout { clockView24 = DateFormat.getBestDateTimePattern(locale, clockView24Skel); + // Use fancy colon. + clockView24 = clockView24.replace(':', '\uee01'); + clockView12 = clockView12.replace(':', '\uee01'); + cacheKey = key; } } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java index a9206e7..48b7be9 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java @@ -237,11 +237,6 @@ public abstract class KeyguardViewBase extends FrameLayout implements SecurityCa if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode())); mSecurityContainer.showPrimarySecurityScreen(false); mSecurityContainer.onResume(KeyguardSecurityView.SCREEN_ON); - - // This is a an attempt to fix bug 7137389 where the device comes back on but the entire - // layout is blank but forcing a layout causes it to reappear (e.g. with with - // hierarchyviewer). - requestLayout(); requestFocus(); } diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 6b62c25..e9cb197 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -52,6 +52,8 @@ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" /> + <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" /> + <!-- Physical hardware --> <uses-permission android:name="android.permission.MANAGE_USB" /> diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_default_user.png Binary files differdeleted file mode 100644 index 18257e0..0000000 --- a/packages/SystemUI/res/drawable-hdpi/ic_qs_default_user.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_default_user.png Binary files differdeleted file mode 100644 index a35c30d..0000000 --- a/packages/SystemUI/res/drawable-mdpi/ic_qs_default_user.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_default_user.png Binary files differdeleted file mode 100644 index d14a67f..0000000 --- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_default_user.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_default_user.png Binary files differdeleted file mode 100644 index 07f16c3..0000000 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_default_user.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable/ic_account_circle.xml b/packages/SystemUI/res/drawable/ic_account_circle.xml new file mode 100644 index 0000000..a7e8514 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_account_circle.xml @@ -0,0 +1,28 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="24dp" + android:height="24dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FFFFFFFF" + android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,5.0c1.7,0.0 3.0,1.3 3.0,3.0c0.0,1.7 -1.3,3.0 -3.0,3.0c-1.7,0.0 -3.0,-1.3 -3.0,-3.0C9.0,6.3 10.3,5.0 12.0,5.0zM12.0,19.2c-2.5,0.0 -4.7,-1.3 -6.0,-3.2c0.0,-2.0 4.0,-3.1 6.0,-3.1c2.0,0.0 6.0,1.1 6.0,3.1C16.7,17.9 14.5,19.2 12.0,19.2z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/notification_header_bg.xml b/packages/SystemUI/res/drawable/notification_header_bg.xml index 09d0d7d..5daec20 100644 --- a/packages/SystemUI/res/drawable/notification_header_bg.xml +++ b/packages/SystemUI/res/drawable/notification_header_bg.xml @@ -19,13 +19,11 @@ <item android:state_pressed="true"> <shape> <solid android:color="@color/background_color_1_press" /> - <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" /> </shape> </item> <item> <shape> <solid android:color="@color/background_color_1" /> - <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" /> </shape> </item> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/qs_panel_background.xml b/packages/SystemUI/res/drawable/qs_panel_background.xml index c324976..a1a5362 100644 --- a/packages/SystemUI/res/drawable/qs_panel_background.xml +++ b/packages/SystemUI/res/drawable/qs_panel_background.xml @@ -13,11 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. --> -<inset xmlns:android="http://schemas.android.com/apk/res/android" - android:insetLeft="@dimen/notification_side_padding" - android:insetRight="@dimen/notification_side_padding"> - <shape> - <solid android:color="@color/system_primary_color" /> - <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" /> - </shape> -</inset> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/system_primary_color" /> + <corners + android:radius="@*android:dimen/notification_quantum_rounded_rect_radius"/> +</shape> diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml index 2ec3766..21e5390 100644 --- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml +++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml @@ -53,7 +53,8 @@ android:layout_marginBottom="100dp" android:layout_gravity="bottom|center_horizontal" android:textStyle="italic" - android:textAppearance="?android:attr/textAppearanceMedium"/> + android:textColor="#ffffff" + android:textAppearance="?android:attr/textAppearanceSmall"/> <ImageView android:id="@+id/lock_icon" diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml index 85de645..398787f 100644 --- a/packages/SystemUI/res/layout/qs_panel.xml +++ b/packages/SystemUI/res/layout/qs_panel.xml @@ -16,11 +16,10 @@ <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/quick_settings_container" - android:paddingLeft="@dimen/notification_side_padding" - android:paddingRight="@dimen/notification_side_padding" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@drawable/qs_panel_background" > + android:background="@drawable/qs_panel_background" + android:elevation="2dp"> <com.android.systemui.qs.QSPanel android:id="@+id/quick_settings_panel" android:background="#0000" diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 2ec9935..cde83bf 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -59,8 +59,8 @@ android:id="@+id/scroll_view" android:layout_width="match_parent" android:layout_height="match_parent" - android:visibility="invisible" android:scrollbars="none" + android:overScrollMode="never" android:fillViewport="true"> <LinearLayout android:layout_width="match_parent" @@ -70,7 +70,9 @@ layout="@layout/qs_panel" android:layout_marginTop="@dimen/status_bar_header_height_expanded" android:layout_width="match_parent" - android:layout_height="wrap_content"/> + android:layout_height="wrap_content" + android:layout_marginLeft="@dimen/notification_side_padding" + android:layout_marginRight="@dimen/notification_side_padding"/> <!-- A view to reserve space for the collapsed stack --> <View @@ -79,7 +81,6 @@ </LinearLayout> </com.android.systemui.statusbar.phone.ObservableScrollView> - <com.android.systemui.statusbar.stack.NotificationStackScrollLayout android:id="@+id/notification_stack_scroller" android:layout_width="match_parent" diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml index 89fa988..dfc3b22 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml @@ -25,7 +25,7 @@ android:paddingStart="@dimen/notification_side_padding" android:paddingEnd="@dimen/notification_side_padding" android:baselineAligned="false" - android:elevation="10dp" + android:elevation="4dp" > <View @@ -65,22 +65,13 @@ /> </RelativeLayout> - <com.android.keyguard.CarrierText - android:id="@+id/keyguard_carrier_text" - android:layout_width="wrap_content" - android:layout_height="@dimen/status_bar_header_height_keyguard" - android:layout_marginLeft="8dp" - android:gravity="center_vertical" - android:ellipsize="marquee" - android:textAppearance="?android:attr/textAppearanceMedium" /> - <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch" android:layout_width="40dp" android:layout_height="@dimen/status_bar_header_height" android:layout_alignParentEnd="true" android:background="@null" android:scaleType="centerInside" - android:padding="6dp" + android:padding="8dp" /> <ImageButton android:id="@+id/settings_button" @@ -98,6 +89,17 @@ android:layout_marginEnd="4dp" /> + <com.android.keyguard.CarrierText + android:id="@+id/keyguard_carrier_text" + android:layout_width="match_parent" + android:layout_height="@dimen/status_bar_header_height_keyguard" + android:layout_marginLeft="8dp" + android:layout_toStartOf="@id/system_icons_container" + android:gravity="center_vertical" + android:ellipsize="marquee" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="#ffffff" /> + <include layout="@layout/quick_settings_brightness_dialog" android:id="@+id/brightness_container" diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index 22815f3..5750faa 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -57,6 +57,6 @@ <!-- The margin between the clock and the notifications on Keyguard. See keyguard_clock_height_fraction_* for the difference between min and max.--> - <dimen name="keyguard_clock_notifications_margin_min">32dp</dimen> - <dimen name="keyguard_clock_notifications_margin_max">32dp</dimen> + <dimen name="keyguard_clock_notifications_margin_min">36dp</dimen> + <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index c209434..bf0cb68 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -196,6 +196,9 @@ <dimen name="qs_dual_tile_height">109dp</dimen> <dimen name="qs_dual_tile_padding">12dp</dimen> + <!-- How far the expanded QS panel peeks from the header in collapsed state. --> + <dimen name="qs_peek_height">8dp</dimen> + <!-- used by DessertCase --> <dimen name="dessert_case_cell_size">192dp</dimen> @@ -246,7 +249,7 @@ <dimen name="notification_side_padding">8dp</dimen> <!-- Z distance between notifications if they are in the stack --> - <dimen name="z_distance_between_notifications">2dp</dimen> + <dimen name="z_distance_between_notifications">1dp</dimen> <!-- The padding between the individual notification cards when dimmed. --> <dimen name="notification_padding_dimmed">0dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java index c0f9bf2..191bac9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java @@ -20,6 +20,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.net.ConnectivityManager; import android.provider.Settings.Global; import com.android.systemui.R; @@ -52,10 +53,9 @@ public class AirplaneModeTile extends QSTile<QSTile.BooleanState> { } private void setEnabled(boolean enabled) { - mSetting.setValue(enabled ? 1 : 0); - final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); - intent.putExtra("state", enabled); - mContext.sendBroadcast(intent); + final ConnectivityManager mgr = + (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + mgr.setAirplaneMode(enabled); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java index ac16164..e3dac4a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java @@ -21,15 +21,25 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.RectF; +import android.graphics.Shader; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; import android.view.animation.PathInterpolator; - import com.android.systemui.R; +import com.android.systemui.statusbar.stack.StackStateAnimator; /** * Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer} @@ -41,6 +51,36 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView private static final int BACKGROUND_ANIMATION_LENGTH_MS = 220; private static final int ACTIVATE_ANIMATION_LENGTH = 220; + /** + * The amount of width, which is kept in the end when performing a disappear animation (also + * the amount from which the horizontal appearing begins) + */ + private static final float HORIZONTAL_COLLAPSED_REST_PARTIAL = 0.05f; + + /** + * At which point from [0,1] does the horizontal collapse animation end (or start when + * expanding)? 1.0 meaning that it ends immediately and 0.0 that it is continuously animated. + */ + private static final float HORIZONTAL_ANIMATION_END = 0.2f; + + /** + * At which point from [0,1] does the alpha animation end (or start when + * expanding)? 1.0 meaning that it ends immediately and 0.0 that it is continuously animated. + */ + private static final float ALPHA_ANIMATION_END = 0.0f; + + /** + * At which point from [0,1] does the horizontal collapse animation start (or start when + * expanding)? 1.0 meaning that it starts immediately and 0.0 that it is animated at all. + */ + private static final float HORIZONTAL_ANIMATION_START = 1.0f; + + /** + * At which point from [0,1] does the vertical collapse animation start (or end when + * expanding) 1.0 meaning that it starts immediately and 0.0 that it is animated at all. + */ + private static final float VERTICAL_ANIMATION_START = 1.0f; + private static final Interpolator ACTIVATE_INVERSE_INTERPOLATOR = new PathInterpolator(0.6f, 0, 0.5f, 1); private static final Interpolator ACTIVATE_INVERSE_ALPHA_INTERPOLATOR @@ -53,6 +93,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView private int mBgTint = 0; private int mDimmedBgTint = 0; + private final int mRoundedRectCornerRadius; /** * Flag to indicate that the notification has been touched once and the second touch will @@ -66,22 +107,41 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView private OnActivatedListener mOnActivatedListener; - private Interpolator mLinearOutSlowInInterpolator; - private Interpolator mFastOutSlowInInterpolator; + private final Interpolator mLinearOutSlowInInterpolator; + private final Interpolator mFastOutSlowInInterpolator; + private final Interpolator mSlowOutFastInInterpolator; + private final Interpolator mSlowOutLinearInInterpolator; + private final Interpolator mLinearInterpolator; + private Interpolator mCurrentAppearInterpolator; + private Interpolator mCurrentAlphaInterpolator; private NotificationBackgroundView mBackgroundNormal; private NotificationBackgroundView mBackgroundDimmed; private ObjectAnimator mBackgroundAnimator; + private RectF mAppearAnimationRect = new RectF(); + private PorterDuffColorFilter mAppearAnimationFilter; + private float mAnimationTranslationY; + private boolean mDrawingAppearAnimation; + private Paint mAppearPaint = new Paint(); + private ValueAnimator mAppearAnimator; + private float mAppearAnimationFraction = -1.0f; + private float mAppearAnimationTranslation; public ActivatableNotificationView(Context context, AttributeSet attrs) { super(context, attrs); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in); + mSlowOutFastInInterpolator = new PathInterpolator(0.8f, 0.0f, 0.6f, 1.0f); mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in); + mSlowOutLinearInInterpolator = new PathInterpolator(0.8f, 0.0f, 1.0f, 1.0f); + mLinearInterpolator = new LinearInterpolator(); setClipChildren(false); setClipToPadding(false); + mAppearAnimationFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP); + mRoundedRectCornerRadius = getResources().getDimensionPixelSize( + com.android.internal.R.dimen.notification_quantum_rounded_rect_radius); } @Override @@ -316,6 +376,202 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mBackgroundDimmed.setClipTopAmount(clipTopAmount); } + @Override + public void performRemoveAnimation(float translationDirection, Runnable onFinishedRunnable) { + enableAppearDrawing(true); + if (mDrawingAppearAnimation) { + startAppearAnimation(false /* isAppearing */, translationDirection, + 0, onFinishedRunnable); + } + } + + @Override + public void performAddAnimation(long delay) { + enableAppearDrawing(true); + if (mDrawingAppearAnimation) { + startAppearAnimation(true /* isAppearing */, -1.0f, delay, null); + } + } + + private void startAppearAnimation(boolean isAppearing, + float translationDirection, long delay, final Runnable onFinishedRunnable) { + if (mAppearAnimator != null) { + mAppearAnimator.cancel(); + } + mAnimationTranslationY = translationDirection * mActualHeight; + if (mAppearAnimationFraction == -1.0f) { + // not initialized yet, we start anew + if (isAppearing) { + mAppearAnimationFraction = 0.0f; + mAppearAnimationTranslation = mAnimationTranslationY; + } else { + mAppearAnimationFraction = 1.0f; + mAppearAnimationTranslation = 0; + } + } + + float targetValue; + if (isAppearing) { + mCurrentAppearInterpolator = mSlowOutFastInInterpolator; + mCurrentAlphaInterpolator = mLinearOutSlowInInterpolator; + targetValue = 1.0f; + } else { + mCurrentAppearInterpolator = mFastOutSlowInInterpolator; + mCurrentAlphaInterpolator = mSlowOutLinearInInterpolator; + targetValue = 0.0f; + } + mAppearAnimator = ValueAnimator.ofFloat(mAppearAnimationFraction, + targetValue); + mAppearAnimator.setInterpolator(mLinearInterpolator); + mAppearAnimator.setDuration( + (long) (StackStateAnimator.ANIMATION_DURATION_APPEAR_DISAPPEAR + * Math.abs(mAppearAnimationFraction - targetValue))); + mAppearAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mAppearAnimationFraction = (float) animation.getAnimatedValue(); + updateAppearAnimationAlpha(); + updateAppearRect(); + invalidate(); + } + }); + if (delay > 0) { + // we need to apply the initial state already to avoid drawn frames in the wrong state + updateAppearAnimationAlpha(); + updateAppearRect(); + mAppearAnimator.setStartDelay(delay); + } + mAppearAnimator.addListener(new AnimatorListenerAdapter() { + private boolean mWasCancelled; + + @Override + public void onAnimationEnd(Animator animation) { + if (onFinishedRunnable != null) { + onFinishedRunnable.run(); + } + if (!mWasCancelled) { + mAppearAnimationFraction = -1; + setOutlineRect(null); + enableAppearDrawing(false); + } + } + + @Override + public void onAnimationStart(Animator animation) { + mWasCancelled = false; + } + + @Override + public void onAnimationCancel(Animator animation) { + mWasCancelled = true; + } + }); + mAppearAnimator.start(); + } + + private void updateAppearRect() { + float inverseFraction = (1.0f - mAppearAnimationFraction); + float translationFraction = mCurrentAppearInterpolator.getInterpolation(inverseFraction); + float translateYTotalAmount = translationFraction * mAnimationTranslationY; + mAppearAnimationTranslation = translateYTotalAmount; + + // handle width animation + float widthFraction = (inverseFraction - (1.0f - HORIZONTAL_ANIMATION_START)) + / (HORIZONTAL_ANIMATION_START - HORIZONTAL_ANIMATION_END); + widthFraction = Math.min(1.0f, Math.max(0.0f, widthFraction)); + widthFraction = mCurrentAppearInterpolator.getInterpolation(widthFraction); + float left = (getWidth() * (0.5f - HORIZONTAL_COLLAPSED_REST_PARTIAL / 2.0f) * + widthFraction); + float right = getWidth() - left; + + // handle top animation + float heightFraction = (inverseFraction - (1.0f - VERTICAL_ANIMATION_START)) / + VERTICAL_ANIMATION_START; + heightFraction = Math.max(0.0f, heightFraction); + heightFraction = mCurrentAppearInterpolator.getInterpolation(heightFraction); + + float top; + float bottom; + if (mAnimationTranslationY > 0.0f) { + bottom = mActualHeight - heightFraction * mAnimationTranslationY * 0.1f + - translateYTotalAmount; + top = bottom * heightFraction; + } else { + top = heightFraction * (mActualHeight + mAnimationTranslationY) * 0.1f - + translateYTotalAmount; + bottom = mActualHeight * (1 - heightFraction) + top * heightFraction; + } + mAppearAnimationRect.set(left, top, right, bottom); + setOutlineRect(left, top + mAppearAnimationTranslation, right, + bottom + mAppearAnimationTranslation); + } + + private void updateAppearAnimationAlpha() { + int backgroundColor = getBackgroundColor(); + if (backgroundColor != -1) { + float contentAlphaProgress = mAppearAnimationFraction; + contentAlphaProgress = contentAlphaProgress / (1.0f - ALPHA_ANIMATION_END); + contentAlphaProgress = Math.min(1.0f, contentAlphaProgress); + contentAlphaProgress = mCurrentAlphaInterpolator.getInterpolation(contentAlphaProgress); + int sourceColor = Color.argb((int) (255 * (1.0f - contentAlphaProgress)), + Color.red(backgroundColor), Color.green(backgroundColor), + Color.blue(backgroundColor)); + mAppearAnimationFilter.setColor(sourceColor); + mAppearPaint.setColorFilter(mAppearAnimationFilter); + } + } + + private int getBackgroundColor() { + // TODO: get real color + return 0xfffafafa; + } + + /** + * When we draw the appear animation, we render the view in a bitmap and render this bitmap + * as a shader of a rect. This call creates the Bitmap and switches the drawing mode, + * such that the normal drawing of the views does not happen anymore. + * + * @param enable Should it be enabled. + */ + private void enableAppearDrawing(boolean enable) { + if (enable != mDrawingAppearAnimation) { + if (enable) { + if (getWidth() == 0 || getActualHeight() == 0) { + // TODO: This should not happen, but it can during expansion. Needs + // investigation + return; + } + Bitmap bitmap = Bitmap.createBitmap(getWidth(), getActualHeight(), + Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + draw(canvas); + mAppearPaint.setShader(new BitmapShader(bitmap, Shader.TileMode.CLAMP, + Shader.TileMode.CLAMP)); + } else { + mAppearPaint.setShader(null); + } + mDrawingAppearAnimation = enable; + invalidate(); + } + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (!mDrawingAppearAnimation) { + super.dispatchDraw(canvas); + } else { + drawAppearRect(canvas); + } + } + + private void drawAppearRect(Canvas canvas) { + canvas.save(); + canvas.translate(0, mAppearAnimationTranslation); + canvas.drawRoundRect(mAppearAnimationRect, mRoundedRectCornerRadius, + mRoundedRectCornerRadius, mAppearPaint); + canvas.restore(); + } + public void setOnActivatedListener(OnActivatedListener onActivatedListener) { mOnActivatedListener = onActivatedListener; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 457d32e..f4db625 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -22,6 +22,7 @@ import android.app.Notification; import android.app.PendingIntent; import android.app.TaskStackBuilder; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -46,6 +47,7 @@ import android.os.UserManager; import android.provider.Settings; import android.service.dreams.DreamService; import android.service.dreams.IDreamManager; +import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import android.text.TextUtils; import android.util.Log; @@ -79,13 +81,17 @@ import com.android.systemui.statusbar.phone.KeyguardTouchDelegate; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; import java.util.ArrayList; +import java.util.Arrays; import java.util.Locale; +import static com.android.keyguard.KeyguardHostView.OnDismissAction; + public abstract class BaseStatusBar extends SystemUI implements CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener { public static final String TAG = "StatusBar"; public static final boolean DEBUG = false; public static final boolean MULTIUSER_DEBUG = false; + private static final boolean USE_NOTIFICATION_LISTENER = false; protected static final int MSG_SHOW_RECENT_APPS = 1019; protected static final int MSG_HIDE_RECENT_APPS = 1020; @@ -158,6 +164,7 @@ public abstract class BaseStatusBar extends SystemUI implements protected WindowManager mWindowManager; protected IWindowManager mWindowManagerService; + protected abstract void refreshLayout(int layoutDirection); protected Display mDisplay; @@ -208,33 +215,47 @@ public abstract class BaseStatusBar extends SystemUI implements private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() { @Override - public boolean onClickHandler(View view, PendingIntent pendingIntent, Intent fillInIntent) { + public boolean onClickHandler( + final View view, final PendingIntent pendingIntent, final Intent fillInIntent) { if (DEBUG) { Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent); } final boolean isActivity = pendingIntent.isActivity(); if (isActivity) { - try { - // The intent we are sending is for the application, which - // won't have permission to immediately start an activity after - // the user switches to home. We know it is safe to do at this - // point, so make sure new activity switches are now allowed. - ActivityManagerNative.getDefault().resumeAppSwitches(); - // Also, notifications can be launched from the lock screen, - // so dismiss the lock screen when the activity starts. - ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); - } catch (RemoteException e) { - } - } + startNotificationActivity(new OnDismissAction() { + @Override + public boolean onDismiss() { + try { + // The intent we are sending is for the application, which + // won't have permission to immediately start an activity after + // the user switches to home. We know it is safe to do at this + // point, so make sure new activity switches are now allowed. + ActivityManagerNative.getDefault().resumeAppSwitches(); + // Also, notifications can be launched from the lock screen, + // so dismiss the lock screen when the activity starts. + ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); + } catch (RemoteException e) { + } - boolean handled = super.onClickHandler(view, pendingIntent, fillInIntent); + boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent); - if (isActivity && handled) { - // close the shade if it was open - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); - visibilityChanged(false); + // close the shade if it was open + if (handled) { + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); + visibilityChanged(false); + } + return handled; // Wait for activity start. + } + }); + return true; + } else { + return super.onClickHandler(view, pendingIntent, fillInIntent); } - return handled; + } + + private boolean superOnClickHandler(View view, PendingIntent pendingIntent, + Intent fillInIntent) { + return super.onClickHandler(view, pendingIntent, fillInIntent); } }; @@ -253,6 +274,49 @@ public abstract class BaseStatusBar extends SystemUI implements } }; + private final NotificationListenerService mNotificationListener = + new NotificationListenerService() { + @Override + public void onListenerConnected() { + if (DEBUG) Log.d(TAG, "onListenerConnected"); + final StatusBarNotification[] notifications = getActiveNotifications(); + mHandler.post(new Runnable() { + @Override + public void run() { + for (StatusBarNotification sbn : notifications) { + addNotificationInternal(sbn); + } + } + }); + } + + @Override + public void onNotificationPosted(final StatusBarNotification sbn) { + if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn); + mHandler.post(new Runnable() { + @Override + public void run() { + if (mNotificationData.findByKey(sbn.getKey()) != null) { + updateNotificationInternal(sbn); + } else { + addNotificationInternal(sbn); + } + } + }); + } + + @Override + public void onNotificationRemoved(final StatusBarNotification sbn) { + if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn); + mHandler.post(new Runnable() { + @Override + public void run() { + removeNotificationInternal(sbn.getKey()); + } + }); + } + }; + private void updateCurrentProfilesCache() { synchronized (mCurrentProfiles) { mCurrentProfiles.clear(); @@ -299,14 +363,13 @@ public abstract class BaseStatusBar extends SystemUI implements // Connect in to the status bar manager service StatusBarIconList iconList = new StatusBarIconList(); - ArrayList<IBinder> notificationKeys = new ArrayList<IBinder>(); ArrayList<StatusBarNotification> notifications = new ArrayList<StatusBarNotification>(); mCommandQueue = new CommandQueue(this, iconList); int[] switches = new int[8]; ArrayList<IBinder> binders = new ArrayList<IBinder>(); try { - mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications, + mBarService.registerStatusBar(mCommandQueue, iconList, notifications, switches, binders); } catch (RemoteException ex) { // If the system process isn't there we're doomed anyway. @@ -332,17 +395,23 @@ public abstract class BaseStatusBar extends SystemUI implements } } - // Set up the initial notification state - N = notificationKeys.size(); - if (N == notifications.size()) { - for (int i=0; i<N; i++) { - addNotification(notificationKeys.get(i), notifications.get(i)); + // Set up the initial notification state. + if (USE_NOTIFICATION_LISTENER) { + try { + mNotificationListener.registerAsSystemService( + new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()), + UserHandle.USER_ALL); + } catch (RemoteException e) { + Log.e(TAG, "Unable to register notification listener", e); } } else { - Log.wtf(TAG, "Notification list length mismatch: keys=" + N - + " notifications=" + notifications.size()); + N = notifications.size(); + for (int i=0; i<N; i++) { + addNotification(notifications.get(i)); + } } + if (DEBUG) { Log.d(TAG, String.format( "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x", @@ -381,6 +450,14 @@ public abstract class BaseStatusBar extends SystemUI implements } } + /** + * Takes the necessary steps to prepare the status bar for starting an activity, then starts it. + * @param action A dismiss action that is called if it's safe to start the activity. + */ + protected void startNotificationActivity(OnDismissAction action) { + action.onDismiss(); + } + @Override protected void onConfigurationChanged(Configuration newConfig) { final Locale locale = mContext.getResources().getConfiguration().locale; @@ -946,47 +1023,55 @@ public abstract class BaseStatusBar extends SystemUI implements mIsHeadsUp = forHun; } - public void onClick(View v) { - try { - // The intent we are sending is for the application, which - // won't have permission to immediately start an activity after - // the user switches to home. We know it is safe to do at this - // point, so make sure new activity switches are now allowed. - ActivityManagerNative.getDefault().resumeAppSwitches(); - // Also, notifications can be launched from the lock screen, - // so dismiss the lock screen when the activity starts. - ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); - } catch (RemoteException e) { - } + public void onClick(final View v) { + startNotificationActivity(new OnDismissAction() { + public boolean onDismiss() { + try { + // The intent we are sending is for the application, which + // won't have permission to immediately start an activity after + // the user switches to home. We know it is safe to do at this + // point, so make sure new activity switches are now allowed. + ActivityManagerNative.getDefault().resumeAppSwitches(); + // Also, notifications can be launched from the lock screen, + // so dismiss the lock screen when the activity starts. + ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); + } catch (RemoteException e) { + } - if (mIntent != null) { - int[] pos = new int[2]; - v.getLocationOnScreen(pos); - Intent overlay = new Intent(); - overlay.setSourceBounds( - new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight())); - try { - mIntent.send(mContext, 0, overlay); - } catch (PendingIntent.CanceledException e) { - // the stack trace isn't very helpful here. Just log the exception message. - Log.w(TAG, "Sending contentIntent failed: " + e); - } + boolean sent = false; + if (mIntent != null) { + int[] pos = new int[2]; + v.getLocationOnScreen(pos); + Intent overlay = new Intent(); + overlay.setSourceBounds(new Rect(pos[0], pos[1], + pos[0]+v.getWidth(), pos[1]+v.getHeight())); + try { + mIntent.send(mContext, 0, overlay); + sent = true; + } catch (PendingIntent.CanceledException e) { + // the stack trace isn't very helpful here. + // Just log the exception message. + Log.w(TAG, "Sending contentIntent failed: " + e); + } + } - KeyguardTouchDelegate.getInstance(mContext).dismiss(); - } + try { + if (mIsHeadsUp) { + mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP); + } + mBarService.onNotificationClick(mNotificationKey); + } catch (RemoteException ex) { + // system process is dead if we're here. + } - try { - if (mIsHeadsUp) { - mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP); - } - mBarService.onNotificationClick(mNotificationKey); - } catch (RemoteException ex) { - // system process is dead if we're here. - } + // close the shade if it was open + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); + visibilityChanged(false); - // close the shade if it was open - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); - visibilityChanged(false); + boolean waitForActivityLaunch = sent && mIntent.isActivity(); + return waitForActivityLaunch; + } + }); } } @@ -1018,8 +1103,8 @@ public abstract class BaseStatusBar extends SystemUI implements * * WARNING: this will call back into us. Don't hold any locks. */ - void handleNotificationError(IBinder key, StatusBarNotification n, String message) { - removeNotification(key); + void handleNotificationError(StatusBarNotification n, String message) { + removeNotification(n.getKey()); try { mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(), n.getInitialPid(), message, n.getUserId()); @@ -1028,7 +1113,7 @@ public abstract class BaseStatusBar extends SystemUI implements } } - protected StatusBarNotification removeNotificationViews(IBinder key) { + protected StatusBarNotification removeNotificationViews(String key) { NotificationData.Entry entry = mNotificationData.remove(key); if (entry == null) { Log.w(TAG, "removeNotification for unknown key: " + key); @@ -1039,14 +1124,14 @@ public abstract class BaseStatusBar extends SystemUI implements if (rowParent != null) rowParent.removeView(entry.row); updateRowStates(); updateNotificationIcons(); + updateSpeedBump(); return entry.notification; } - protected NotificationData.Entry createNotificationViews(IBinder key, - StatusBarNotification notification) { + protected NotificationData.Entry createNotificationViews(StatusBarNotification notification) { if (DEBUG) { - Log.d(TAG, "createNotificationViews(key=" + key + ", notification=" + notification); + Log.d(TAG, "createNotificationViews(notification=" + notification); } // Construct the icon. final StatusBarIconView iconView = new StatusBarIconView(mContext, @@ -1061,13 +1146,13 @@ public abstract class BaseStatusBar extends SystemUI implements notification.getNotification().number, notification.getNotification().tickerText); if (!iconView.set(ic)) { - handleNotificationError(key, notification, "Couldn't create icon: " + ic); + handleNotificationError(notification, "Couldn't create icon: " + ic); return null; } // Construct the expanded view. - NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView); + NotificationData.Entry entry = new NotificationData.Entry(notification, iconView); if (!inflateViews(entry, mStackScroller)) { - handleNotificationError(key, notification, "Couldn't expand RemoteViews for: " + handleNotificationError(notification, "Couldn't expand RemoteViews for: " + notification); return null; } @@ -1083,12 +1168,26 @@ public abstract class BaseStatusBar extends SystemUI implements if (DEBUG) { Log.d(TAG, "addNotificationViews: added at " + pos); } - updateNotificationIcons(); updateRowStates(); + updateNotificationIcons(); + updateSpeedBump(); + } + + protected void updateSpeedBump() { + int n = mNotificationData.size(); + int speedBumpIndex = -1; + for (int i = n-1; i >= 0; i--) { + NotificationData.Entry entry = mNotificationData.get(i); + if (entry.row.getVisibility() != View.GONE && speedBumpIndex == -1 + && entry.row.isBelowSpeedBump() ) { + speedBumpIndex = n - 1 - i; + } + } + mStackScroller.updateSpeedBumpIndex(speedBumpIndex); } - private void addNotificationViews(IBinder key, StatusBarNotification notification) { - addNotificationViews(createNotificationViews(key, notification)); + private void addNotificationViews(StatusBarNotification notification) { + addNotificationViews(createNotificationViews(notification)); } /** @@ -1104,7 +1203,6 @@ public abstract class BaseStatusBar extends SystemUI implements mKeyguardIconOverflowContainer.getIconsView().removeAllViews(); int n = mNotificationData.size(); int visibleNotifications = 0; - int speedBumpIndex = -1; boolean onKeyguard = mState == StatusBarState.KEYGUARD; for (int i = n-1; i >= 0; i--) { NotificationData.Entry entry = mNotificationData.get(i); @@ -1125,17 +1223,14 @@ public abstract class BaseStatusBar extends SystemUI implements mKeyguardIconOverflowContainer.getIconsView().addNotification(entry); } } else { - if (entry.row.getVisibility() == View.GONE) { + boolean wasGone = entry.row.getVisibility() == View.GONE; + entry.row.setVisibility(View.VISIBLE); + if (wasGone) { // notify the scroller of a child addition mStackScroller.generateAddAnimation(entry.row); } - entry.row.setVisibility(View.VISIBLE); visibleNotifications++; } - if (entry.row.getVisibility() != View.GONE && speedBumpIndex == -1 - && entry.row.isBelowSpeedBump() ) { - speedBumpIndex = n - 1 - i; - } } if (onKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) { @@ -1143,8 +1238,6 @@ public abstract class BaseStatusBar extends SystemUI implements } else { mKeyguardIconOverflowContainer.setVisibility(View.GONE); } - - mStackScroller.updateSpeedBumpIndex(speedBumpIndex); } private boolean shouldShowOnKeyguard(StatusBarNotification sbn) { @@ -1160,7 +1253,7 @@ public abstract class BaseStatusBar extends SystemUI implements protected abstract void haltTicker(); protected abstract void setAreThereNotifications(); protected abstract void updateNotificationIcons(); - protected abstract void tick(IBinder key, StatusBarNotification n, boolean firstTime); + protected abstract void tick(StatusBarNotification n, boolean firstTime); protected abstract void updateExpandedViewPos(int expandedPosition); protected abstract boolean shouldDisableNavbarGestures(); @@ -1168,12 +1261,37 @@ public abstract class BaseStatusBar extends SystemUI implements return parent != null && parent.indexOfChild(entry.row) == 0; } - public void updateNotification(IBinder key, StatusBarNotification notification) { - if (DEBUG) Log.d(TAG, "updateNotification(" + key + " -> " + notification + ")"); - final NotificationData.Entry oldEntry = mNotificationData.findByKey(key); + @Override + public void addNotification(StatusBarNotification notification) { + if (!USE_NOTIFICATION_LISTENER) { + addNotificationInternal(notification); + } + } + + public abstract void addNotificationInternal(StatusBarNotification notification); + + @Override + public void removeNotification(String key) { + if (!USE_NOTIFICATION_LISTENER) { + removeNotificationInternal(key); + } + } + + protected abstract void removeNotificationInternal(String key); + + public void updateNotification(StatusBarNotification notification) { + if (!USE_NOTIFICATION_LISTENER) { + updateNotificationInternal(notification); + } + } + + public void updateNotificationInternal(StatusBarNotification notification) { + if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")"); + + final NotificationData.Entry oldEntry = mNotificationData.findByKey(notification.getKey()); if (oldEntry == null) { - Log.w(TAG, "updateNotification for unknown key: " + key); + Log.w(TAG, "updateNotification for unknown key: " + notification.getKey()); return; } @@ -1244,15 +1362,15 @@ public abstract class BaseStatusBar extends SystemUI implements boolean orderUnchanged = notification.getNotification().when == oldNotification.getNotification().when && notification.getScore() == oldNotification.getScore(); - // score now encompasses/supersedes isOngoing() + // score now encompasses/supersedes isOngoing() boolean updateTicker = notification.getNotification().tickerText != null && !TextUtils.equals(notification.getNotification().tickerText, - oldEntry.notification.getNotification().tickerText); + oldEntry.notification.getNotification().tickerText); boolean isTopAnyway = isTopNotification(rowParent, oldEntry); if (contentsUnchanged && bigContentsUnchanged && headsUpContentsUnchanged && publicUnchanged && (orderUnchanged || isTopAnyway)) { - if (DEBUG) Log.d(TAG, "reusing notification for key: " + key); + if (DEBUG) Log.d(TAG, "reusing notification for key: " + notification.getKey()); oldEntry.notification = notification; try { updateNotificationViews(oldEntry, notification); @@ -1276,25 +1394,27 @@ public abstract class BaseStatusBar extends SystemUI implements notification.getNotification().number, notification.getNotification().tickerText); if (!oldEntry.icon.set(ic)) { - handleNotificationError(key, notification, "Couldn't update icon: " + ic); + handleNotificationError(notification, "Couldn't update icon: " + ic); return; } updateRowStates(); + updateSpeedBump(); } catch (RuntimeException e) { // It failed to add cleanly. Log, and remove the view from the panel. Log.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e); - removeNotificationViews(key); - addNotificationViews(key, notification); + removeNotificationViews(notification.getKey()); + addNotificationViews(notification); } } else { - if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key); + if (DEBUG) Log.d(TAG, "not reusing notification for key: " + notification.getKey()); if (DEBUG) Log.d(TAG, "contents was " + (contentsUnchanged ? "unchanged" : "changed")); if (DEBUG) Log.d(TAG, "order was " + (orderUnchanged ? "unchanged" : "changed")); if (DEBUG) Log.d(TAG, "notification is " + (isTopAnyway ? "top" : "not top")); - removeNotificationViews(key); - addNotificationViews(key, notification); // will also replace the heads up - final NotificationData.Entry newEntry = mNotificationData.findByKey(key); + removeNotificationViews(notification.getKey()); + addNotificationViews(notification); // will also replace the heads up + final NotificationData.Entry newEntry = mNotificationData.findByKey( + notification.getKey()); final boolean userChangedExpansion = oldEntry.row.hasUserChangedExpansion(); if (userChangedExpansion) { boolean userExpanded = oldEntry.row.isUserExpanded(); @@ -1314,7 +1434,7 @@ public abstract class BaseStatusBar extends SystemUI implements // Restart the ticker if it's still running if (updateTicker && isForCurrentUser) { haltTicker(); - tick(key, notification, false); + tick(notification, false); } // Recalculate the position of the sliding windows and the titles. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index b4a347b..aaeadb6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -21,7 +21,6 @@ import android.os.IBinder; import android.os.Message; import android.service.notification.StatusBarNotification; -import com.android.internal.policy.IKeyguardShowCallback; import com.android.internal.statusbar.IStatusBar; import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.statusbar.StatusBarIconList; @@ -73,11 +72,6 @@ public class CommandQueue extends IStatusBar.Stub { private Callbacks mCallbacks; private Handler mHandler = new H(); - private class NotificationQueueEntry { - IBinder key; - StatusBarNotification notification; - } - /** * These methods are called back on the main thread. */ @@ -86,9 +80,9 @@ public class CommandQueue extends IStatusBar.Stub { public void updateIcon(String slot, int index, int viewIndex, StatusBarIcon old, StatusBarIcon icon); public void removeIcon(String slot, int index, int viewIndex); - public void addNotification(IBinder key, StatusBarNotification notification); - public void updateNotification(IBinder key, StatusBarNotification notification); - public void removeNotification(IBinder key); + public void addNotification(StatusBarNotification notification); + public void updateNotification(StatusBarNotification notification); + public void removeNotification(String key); public void disable(int state); public void animateExpandNotificationsPanel(); public void animateCollapsePanels(int flags); @@ -106,7 +100,6 @@ public class CommandQueue extends IStatusBar.Stub { public void showSearchPanel(); public void hideSearchPanel(); public void setWindowState(int window, int state); - } public CommandQueue(Callbacks callbacks, StatusBarIconList list) { @@ -130,25 +123,21 @@ public class CommandQueue extends IStatusBar.Stub { } } - public void addNotification(IBinder key, StatusBarNotification notification) { + @Override + public void addNotification(StatusBarNotification notification) { synchronized (mList) { - NotificationQueueEntry ne = new NotificationQueueEntry(); - ne.key = key; - ne.notification = notification; - mHandler.obtainMessage(MSG_ADD_NOTIFICATION, 0, 0, ne).sendToTarget(); + mHandler.obtainMessage(MSG_ADD_NOTIFICATION, 0, 0, notification).sendToTarget(); } } - public void updateNotification(IBinder key, StatusBarNotification notification) { + @Override + public void updateNotification(StatusBarNotification notification) { synchronized (mList) { - NotificationQueueEntry ne = new NotificationQueueEntry(); - ne.key = key; - ne.notification = notification; - mHandler.obtainMessage(MSG_UPDATE_NOTIFICATION, 0, 0, ne).sendToTarget(); + mHandler.obtainMessage(MSG_UPDATE_NOTIFICATION, 0, 0, notification).sendToTarget(); } } - public void removeNotification(IBinder key) { + public void removeNotification(String key) { synchronized (mList) { mHandler.obtainMessage(MSG_REMOVE_NOTIFICATION, 0, 0, key).sendToTarget(); } @@ -291,17 +280,15 @@ public class CommandQueue extends IStatusBar.Stub { break; } case MSG_ADD_NOTIFICATION: { - final NotificationQueueEntry ne = (NotificationQueueEntry)msg.obj; - mCallbacks.addNotification(ne.key, ne.notification); + mCallbacks.addNotification((StatusBarNotification) msg.obj); break; } case MSG_UPDATE_NOTIFICATION: { - final NotificationQueueEntry ne = (NotificationQueueEntry)msg.obj; - mCallbacks.updateNotification(ne.key, ne.notification); + mCallbacks.updateNotification((StatusBarNotification) msg.obj); break; } case MSG_REMOVE_NOTIFICATION: { - mCallbacks.removeNotification((IBinder)msg.obj); + mCallbacks.removeNotification((String) msg.obj); break; } case MSG_DISABLE: diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java index a42c194..843db04 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java @@ -18,8 +18,8 @@ package com.android.systemui.statusbar; import android.content.Context; import android.graphics.Outline; +import android.graphics.RectF; import android.util.AttributeSet; -import android.widget.FrameLayout; /** * Like {@link ExpandableView}, but setting an outline for the height and clipping. @@ -27,9 +27,12 @@ import android.widget.FrameLayout; public abstract class ExpandableOutlineView extends ExpandableView { private final Outline mOutline = new Outline(); + private boolean mCustomOutline; + private float mDensity; public ExpandableOutlineView(Context context, AttributeSet attrs) { super(context, attrs); + mDensity = getResources().getDisplayMetrics().density; } @Override @@ -50,11 +53,37 @@ public abstract class ExpandableOutlineView extends ExpandableView { updateOutline(); } - private void updateOutline() { - mOutline.setRect(0, - mClipTopAmount, - getWidth(), - Math.max(mActualHeight, mClipTopAmount)); + protected void setOutlineRect(RectF rect) { + if (rect != null) { + setOutlineRect(rect.left, rect.top, rect.right, rect.bottom); + } else { + mCustomOutline = false; + updateOutline(); + } + } + + protected void setOutlineRect(float left, float top, float right, float bottom) { + mCustomOutline = true; + + int rectLeft = (int) left; + int rectTop = (int) top; + int rectRight = (int) right; + int rectBottom = (int) bottom; + + // Outlines need to be at least 1 dp + rectBottom = (int) Math.max(top + mDensity, rectBottom); + rectRight = (int) Math.max(left + mDensity, rectRight); + mOutline.setRect(rectLeft, rectTop, rectRight, rectBottom); setOutline(mOutline); } + + private void updateOutline() { + if (!mCustomOutline) { + mOutline.setRect(0, + mClipTopAmount, + getWidth(), + Math.max(mActualHeight, mClipTopAmount)); + setOutline(mOutline); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java index eaaac10..088f076 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java @@ -205,6 +205,21 @@ public abstract class ExpandableView extends FrameLayout { } /** + * Perform a remove animation on this view. + * + * @param translationDirection The direction value from [-1 ... 1] indicating in which the + * animation should be performed. A value of -1 means that The + * remove animation should be performed upwards, + * such that the child appears to be going away to the top. 1 + * Should mean the opposite. + * @param onFinishedRunnable A runnable which should be run when the animation is finished. + */ + public abstract void performRemoveAnimation(float translationDirection, + Runnable onFinishedRunnable); + + public abstract void performAddAnimation(long delay); + + /** * A listener notifying when {@link #getActualHeight} changes. */ public interface OnHeightChangedListener { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java index 8440b9f..0555879 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java @@ -18,8 +18,6 @@ package com.android.systemui.statusbar; import android.app.Notification; import android.content.Context; -import android.os.Binder; -import android.os.IBinder; import android.os.Process; import android.provider.Settings; import android.service.notification.StatusBarNotification; @@ -33,13 +31,14 @@ import com.android.systemui.statusbar.phone.PhoneStatusBar; public class InterceptedNotifications { private static final String TAG = "InterceptedNotifications"; private static final String EXTRA_INTERCEPT = "android.intercept"; + private static final String SYNTHETIC_KEY = "InterceptedNotifications.SYNTHETIC_KEY"; private final Context mContext; private final PhoneStatusBar mBar; - private final ArrayMap<IBinder, StatusBarNotification> mIntercepted - = new ArrayMap<IBinder, StatusBarNotification>(); + private final ArrayMap<String, StatusBarNotification> mIntercepted + = new ArrayMap<String, StatusBarNotification>(); - private Binder mSynKey; + private String mSynKey; public InterceptedNotifications(Context context, PhoneStatusBar bar) { mContext = context; @@ -49,36 +48,35 @@ public class InterceptedNotifications { public void releaseIntercepted() { final int n = mIntercepted.size(); for (int i = 0; i < n; i++) { - final IBinder key = mIntercepted.keyAt(i); final StatusBarNotification sbn = mIntercepted.valueAt(i); sbn.getNotification().extras.putBoolean(EXTRA_INTERCEPT, false); - mBar.addNotification(key, sbn); + mBar.addNotificationInternal(sbn); } mIntercepted.clear(); updateSyntheticNotification(); } - public boolean tryIntercept(IBinder key, StatusBarNotification notification) { + public boolean tryIntercept(StatusBarNotification notification) { if (!notification.getNotification().extras.getBoolean(EXTRA_INTERCEPT)) return false; if (shouldDisplayIntercepted()) return false; - mIntercepted.put(key, notification); + mIntercepted.put(notification.getKey(), notification); updateSyntheticNotification(); return true; } - public void remove(IBinder key) { + public void remove(String key) { if (mIntercepted.remove(key) != null) { updateSyntheticNotification(); } } public boolean isSyntheticEntry(Entry ent) { - return mSynKey != null && ent.key.equals(mSynKey); + return ent.key.equals(SYNTHETIC_KEY); } - public void update(IBinder key, StatusBarNotification notification) { - if (mIntercepted.containsKey(key)) { - mIntercepted.put(key, notification); + public void update(StatusBarNotification notification) { + if (mIntercepted.containsKey(notification.getKey())) { + mIntercepted.put(notification.getKey(), notification); } } @@ -90,7 +88,7 @@ public class InterceptedNotifications { private void updateSyntheticNotification() { if (mIntercepted.isEmpty()) { if (mSynKey != null) { - mBar.removeNotification(mSynKey); + mBar.removeNotificationInternal(mSynKey); mSynKey = null; } return; @@ -108,10 +106,10 @@ public class InterceptedNotifications { TAG.hashCode(), TAG, Process.myUid(), Process.myPid(), 0, n, mBar.getCurrentUserHandle()); if (mSynKey == null) { - mSynKey = new Binder(); - mBar.addNotification(mSynKey, sbn); + mSynKey = sbn.getKey(); + mBar.addNotificationInternal(sbn); } else { - mBar.updateNotification(mSynKey, sbn); + mBar.updateNotificationInternal(sbn); } final NotificationData.Entry entry = mBar.mNotificationData.findByKey(mSynKey); entry.row.setOnClickListener(mSynClickListener); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java index 3c080fe..1c2ca91 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java @@ -34,7 +34,6 @@ public class NotificationBackgroundView extends View { public NotificationBackgroundView(Context context, AttributeSet attrs) { super(context, attrs); - setWillNotDraw(false); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java index b1a5750..5696246 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java @@ -16,7 +16,6 @@ package com.android.systemui.statusbar; -import android.os.IBinder; import android.service.notification.StatusBarNotification; import android.view.View; import android.widget.ImageView; @@ -29,7 +28,7 @@ import java.util.Comparator; */ public class NotificationData { public static final class Entry { - public IBinder key; + public String key; public StatusBarNotification notification; public StatusBarIconView icon; public ExpandableNotificationRow row; // the outer expanded view @@ -39,8 +38,8 @@ public class NotificationData { public View expandedBig; private boolean interruption; public Entry() {} - public Entry(IBinder key, StatusBarNotification n, StatusBarIconView ic) { - this.key = key; + public Entry(StatusBarNotification n, StatusBarIconView ic) { + this.key = n.getKey(); this.notification = n; this.icon = ic; } @@ -63,6 +62,7 @@ public class NotificationData { interruption = true; } } + private final ArrayList<Entry> mEntries = new ArrayList<Entry>(); private final Comparator<Entry> mEntryCmp = new Comparator<Entry>() { // sort first by score, then by when @@ -88,9 +88,9 @@ public class NotificationData { return mEntries.get(i); } - public Entry findByKey(IBinder key) { + public Entry findByKey(String key) { for (Entry e : mEntries) { - if (e.key == key) { + if (e.key.equals(key)) { return e; } } @@ -100,7 +100,7 @@ public class NotificationData { public int add(Entry entry) { int i; int N = mEntries.size(); - for (i=0; i<N; i++) { + for (i = 0; i < N; i++) { if (mEntryCmp.compare(mEntries.get(i), entry) > 0) { break; } @@ -109,7 +109,7 @@ public class NotificationData { return i; } - public Entry remove(IBinder key) { + public Entry remove(String key) { Entry e = findByKey(key); if (e != null) { mEntries.remove(e); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java index 8ae503a..a84daef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java @@ -103,7 +103,11 @@ public class SpeedBumpView extends ExpandableView implements View.OnClickListene @Override public int getIntrinsicHeight() { - return getActualHeight(); + if (mCurrentAnimator != null) { + // expand animation is running + return getActualHeight(); + } + return mIsExpanded ? getHeight() : mCollapsedHeight; } @Override @@ -184,7 +188,7 @@ public class SpeedBumpView extends ExpandableView implements View.OnClickListene } public void performVisibilityAnimation(boolean nowVisible) { - animateDivider(nowVisible); + animateDivider(nowVisible, null /* onFinishedRunnable */); // Animate explanation Text if (mIsExpanded) { @@ -192,7 +196,14 @@ public class SpeedBumpView extends ExpandableView implements View.OnClickListene } } - public void animateDivider(boolean nowVisible) { + /** + * Animate the divider to a new visibility. + * + * @param nowVisible should it now be visible + * @param onFinishedRunnable A runnable which should be run when the animation is + * finished. + */ + public void animateDivider(boolean nowVisible, Runnable onFinishedRunnable) { if (nowVisible != mDividerVisible) { // Animate dividers float endValue = nowVisible ? 1.0f : 0.0f; @@ -204,7 +215,8 @@ public class SpeedBumpView extends ExpandableView implements View.OnClickListene .scaleX(endValue) .scaleY(endValue) .translationX(endTranslationXLeft) - .setInterpolator(mFastOutSlowInInterpolator); + .setInterpolator(mFastOutSlowInInterpolator) + .withEndAction(onFinishedRunnable); mLineRight.animate() .alpha(endValue) .withLayer() @@ -216,6 +228,10 @@ public class SpeedBumpView extends ExpandableView implements View.OnClickListene // Animate dots mDots.performVisibilityAnimation(nowVisible); mDividerVisible = nowVisible; + } else { + if (onFinishedRunnable != null) { + onFinishedRunnable.run(); + } } } @@ -250,6 +266,16 @@ public class SpeedBumpView extends ExpandableView implements View.OnClickListene } } + @Override + public void performRemoveAnimation(float translationDirection, Runnable onFinishedRunnable) { + performVisibilityAnimation(false); + } + + @Override + public void performAddAnimation(long delay) { + performVisibilityAnimation(true); + } + private void resetExplanationText() { mExplanationText.setTranslationY(0); mExplanationText.setVisibility(INVISIBLE); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index d8e1766..2fa2a00 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -28,6 +28,7 @@ import com.android.keyguard.R; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.keyguard.KeyguardViewMediator; +import static com.android.keyguard.KeyguardHostView.OnDismissAction; import static com.android.keyguard.KeyguardSecurityModel.*; /** @@ -64,11 +65,16 @@ public class KeyguardBouncer { // Keyguard. If we need to authenticate, show the bouncer. if (!mKeyguardView.dismiss()) { mRoot.setVisibility(View.VISIBLE); - mKeyguardView.requestFocus(); mKeyguardView.onResume(); } } + public void showWithDismissAction(OnDismissAction r) { + ensureView(); + mKeyguardView.setOnDismissAction(r); + show(); + } + public void hide() { if (mKeyguardView != null) { mKeyguardView.cleanUp(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java new file mode 100644 index 0000000..6a83a5e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.statusbar.phone; + +import android.content.res.Resources; +import android.graphics.Path; +import android.view.animation.PathInterpolator; + +import com.android.systemui.R; + +/** + * Utility class to calculate the clock position and top padding of notifications on Keyguard. + */ +public class KeyguardClockPositionAlgorithm { + + private static final float SLOW_DOWN_FACTOR = 0.4f; + + private static final float CLOCK_RUBBERBAND_FACTOR_MIN = 0.08f; + private static final float CLOCK_RUBBERBAND_FACTOR_MAX = 0.8f; + + private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MIN = 1.4f; + private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MAX = 3.2f; + + private int mClockNotificationsMarginMin; + private int mClockNotificationsMarginMax; + private float mClockYFractionMin; + private float mClockYFractionMax; + private int mMaxKeyguardNotifications; + private int mMaxPanelHeight; + private float mExpandedHeight; + private int mNotificationCount; + private int mHeight; + private int mKeyguardStatusHeight; + + /** + * The number (fractional) of notifications the "more" card counts when calculating how many + * notifications are currently visible for the y positioning of the clock. + */ + private float mMoreCardNotificationAmount; + + private static final PathInterpolator sSlowDownInterpolator; + + static { + Path path = new Path(); + path.moveTo(0, 0); + path.cubicTo(0.3f, 0.875f, 0.6f, 1f, 1f, 1f); + sSlowDownInterpolator = new PathInterpolator(path); + } + + /** + * Refreshes the dimension values. + */ + public void loadDimens(Resources res) { + mClockNotificationsMarginMin = res.getDimensionPixelSize( + R.dimen.keyguard_clock_notifications_margin_min); + mClockNotificationsMarginMax = res.getDimensionPixelSize( + R.dimen.keyguard_clock_notifications_margin_max); + mClockYFractionMin = res.getFraction(R.fraction.keyguard_clock_y_fraction_min, 1, 1); + mClockYFractionMax = res.getFraction(R.fraction.keyguard_clock_y_fraction_max, 1, 1); + mMoreCardNotificationAmount = + (float) res.getDimensionPixelSize(R.dimen.notification_summary_height) / + res.getDimensionPixelSize(R.dimen.notification_min_height); + } + + public void setup(int maxKeyguardNotifications, int maxPanelHeight, float expandedHeight, + int notificationCount, int height, int keyguardStatusHeight) { + mMaxKeyguardNotifications = maxKeyguardNotifications; + mMaxPanelHeight = maxPanelHeight; + mExpandedHeight = expandedHeight; + mNotificationCount = notificationCount; + mHeight = height; + mKeyguardStatusHeight = keyguardStatusHeight; + } + + public void run(Result result) { + int y = getClockY() - mKeyguardStatusHeight/2; + float clockAdjustment = getClockYExpansionAdjustment(); + float topPaddingAdjMultiplier = getTopPaddingAdjMultiplier(); + result.stackScrollerPaddingAdjustment = (int) (clockAdjustment*topPaddingAdjMultiplier); + int clockNotificationsPadding = getClockNotificationsPadding() + + result.stackScrollerPaddingAdjustment; + int padding = y + clockNotificationsPadding; + y += clockAdjustment; + result.clockY = y; + result.stackScrollerPadding = mKeyguardStatusHeight + padding; + result.clockAlpha = getClockAlpha(result.stackScrollerPadding + - (y + mKeyguardStatusHeight)); + } + + private int getClockNotificationsPadding() { + float t = getNotificationAmountT(); + t = Math.min(t, 1.0f); + return (int) (t * mClockNotificationsMarginMin + (1 - t) * mClockNotificationsMarginMax); + } + + private float getClockYFraction() { + float t = getNotificationAmountT(); + t = Math.min(t, 1.0f); + return (1 - t) * mClockYFractionMax + t * mClockYFractionMin; + } + + private int getClockY() { + return (int) (getClockYFraction() * mHeight); + } + + private float getClockYExpansionAdjustment() { + float rubberbandFactor = getClockYExpansionRubberbandFactor(); + float value = (rubberbandFactor * (mMaxPanelHeight - mExpandedHeight)); + float t = value / mMaxPanelHeight; + float slowedDownValue = -sSlowDownInterpolator.getInterpolation(t) * SLOW_DOWN_FACTOR + * mMaxPanelHeight; + if (mNotificationCount == 0) { + return (-2*value + slowedDownValue)/3; + } else { + return slowedDownValue; + } + } + + private float getClockYExpansionRubberbandFactor() { + float t = getNotificationAmountT(); + t = Math.min(t, 1.0f); + t = (float) Math.pow(t, 0.3f); + return (1 - t) * CLOCK_RUBBERBAND_FACTOR_MAX + t * CLOCK_RUBBERBAND_FACTOR_MIN; + } + + private float getTopPaddingAdjMultiplier() { + float t = getNotificationAmountT(); + t = Math.min(t, 1.0f); + return (1 - t) * CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MIN + + t * CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MAX; + } + + private float getClockAlpha(int clockNotificationPadding) { + float t = getNotificationAmountT(); + t = (float) Math.pow(t, 0.3f); + float multiplier = 1 + 2 * (1 - t); + float alpha = 1 + (float) clockNotificationPadding * multiplier / mKeyguardStatusHeight * 3; + return Math.max(0, Math.min(1, alpha)); + } + + /** + * @return a value from 0 to 1 depending on how many notification there are + */ + private float getNotificationAmountT() { + return mNotificationCount + / (mMaxKeyguardNotifications + mMoreCardNotificationAmount); + } + + public static class Result { + + /** + * The y translation of the clock. + */ + public int clockY; + + /** + * The alpha value of the clock. + */ + public float clockAlpha; + + /** + * The top padding of the stack scroller, in pixels. + */ + public int stackScrollerPadding; + + /** + * The top padding adjustment of the stack scroller, in pixels. This value is used to adjust + * the padding, but not the overall panel size. + */ + public int stackScrollerPaddingAdjustment; + } +} 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 123a4f0..f5252a3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.phone; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; -import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; import android.content.Context; import android.util.AttributeSet; @@ -48,6 +47,7 @@ public class NotificationPanelView extends PanelView implements PhoneStatusBar mStatusBar; private StatusBarHeaderView mHeader; private View mQsContainer; + private View mQsPanel; private View mKeyguardStatusView; private ObservableScrollView mScrollView; private View mStackScrollerContainer; @@ -66,6 +66,7 @@ public class NotificationPanelView extends PanelView implements */ private boolean mIntercepting; private boolean mQsExpanded; + private boolean mKeyguardShowing; private float mInitialHeightOnTouch; private float mInitialTouchX; private float mInitialTouchY; @@ -75,6 +76,7 @@ public class NotificationPanelView extends PanelView implements private int mQsMinExpansionHeight; private int mQsMaxExpansionHeight; private int mMinStackHeight; + private int mQsPeekHeight; private float mNotificationTranslation; private int mStackScrollerIntrinsicPadding; private boolean mQsExpansionEnabled = true; @@ -82,19 +84,14 @@ public class NotificationPanelView extends PanelView implements private FlingAnimationUtils mFlingAnimationUtils; private int mStatusBarMinHeight; - private int mClockNotificationsMarginMin; - private int mClockNotificationsMarginMax; - private float mClockYFractionMin; - private float mClockYFractionMax; private Interpolator mFastOutSlowInInterpolator; private ObjectAnimator mClockAnimator; private int mClockAnimationTarget = -1; - - /** - * The number (fractional) of notifications the "more" card counts when calculating how many - * notifications are currently visible for the y positioning of the clock. - */ - private float mMoreCardNotificationAmount; + private int mTopPaddingAdjustment; + private KeyguardClockPositionAlgorithm mClockPositionAlgorithm = + new KeyguardClockPositionAlgorithm(); + private KeyguardClockPositionAlgorithm.Result mClockPositionResult = + new KeyguardClockPositionAlgorithm.Result(); public NotificationPanelView(Context context, AttributeSet attrs) { super(context, attrs); @@ -124,6 +121,7 @@ public class NotificationPanelView extends PanelView implements mKeyguardStatusView = findViewById(R.id.keyguard_status_view); mStackScrollerContainer = findViewById(R.id.notification_container_parent); mQsContainer = findViewById(R.id.quick_settings_container); + mQsPanel = findViewById(R.id.quick_settings_panel); mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view); mScrollView.setListener(this); mNotificationStackScroller = (NotificationStackScrollLayout) @@ -139,34 +137,24 @@ public class NotificationPanelView extends PanelView implements mNotificationTopPadding = getResources().getDimensionPixelSize( R.dimen.notifications_top_padding); mMinStackHeight = getResources().getDimensionPixelSize(R.dimen.collapsed_stack_height); - mClockNotificationsMarginMin = getResources().getDimensionPixelSize( - R.dimen.keyguard_clock_notifications_margin_min); - mClockNotificationsMarginMax = getResources().getDimensionPixelSize( - R.dimen.keyguard_clock_notifications_margin_max); - mClockYFractionMin = - getResources().getFraction(R.fraction.keyguard_clock_y_fraction_min, 1, 1); - mClockYFractionMax = - getResources().getFraction(R.fraction.keyguard_clock_y_fraction_max, 1, 1); - mMoreCardNotificationAmount = - (float) getResources().getDimensionPixelSize(R.dimen.notification_summary_height) / - getResources().getDimensionPixelSize(R.dimen.notification_min_height); mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.4f); mStatusBarMinHeight = getResources().getDimensionPixelSize( com.android.internal.R.dimen.status_bar_height); + mQsPeekHeight = getResources().getDimensionPixelSize(R.dimen.qs_peek_height); + mClockPositionAlgorithm.loadDimens(getResources()); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); - if (!mQsExpanded) { - positionClockAndNotifications(); - } // Calculate quick setting heights. - mQsMinExpansionHeight = mHeader.getCollapsedHeight(); + mQsMinExpansionHeight = mHeader.getCollapsedHeight() + mQsPeekHeight; mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getHeight(); - if (mQsExpansionHeight == 0) { - mQsExpansionHeight = mQsMinExpansionHeight; + if (!mQsExpanded) { + setQsExpansion(mQsMinExpansionHeight); + positionClockAndNotifications(); + mNotificationStackScroller.setStackHeight(getExpandedHeight()); } } @@ -177,17 +165,26 @@ public class NotificationPanelView extends PanelView implements private void positionClockAndNotifications() { boolean animateClock = mNotificationStackScroller.isAddOrRemoveAnimationPending(); if (mStatusBar.getBarState() != StatusBarState.KEYGUARD) { - mStackScrollerIntrinsicPadding = mHeader.getBottom() + mNotificationTopPadding; + mStackScrollerIntrinsicPadding = mHeader.getBottom() + mQsPeekHeight + + mNotificationTopPadding; + mTopPaddingAdjustment = 0; } else { - int notificationCount = mNotificationStackScroller.getNotGoneChildCount(); - int y = getClockY(notificationCount) - mKeyguardStatusView.getHeight()/2; - int padding = getClockNotificationsPadding(notificationCount); + mClockPositionAlgorithm.setup( + mStatusBar.getMaxKeyguardNotifications(), + getMaxPanelHeight(), + getExpandedHeight(), + mNotificationStackScroller.getNotGoneChildCount(), + getHeight(), + mKeyguardStatusView.getHeight()); + mClockPositionAlgorithm.run(mClockPositionResult); if (animateClock || mClockAnimator != null) { - startClockAnimation(y); + startClockAnimation(mClockPositionResult.clockY); } else { - mKeyguardStatusView.setY(y); + mKeyguardStatusView.setY(mClockPositionResult.clockY); } - mStackScrollerIntrinsicPadding = y + mKeyguardStatusView.getHeight() + padding; + applyClockAlpha(mClockPositionResult.clockAlpha); + mStackScrollerIntrinsicPadding = mClockPositionResult.stackScrollerPadding; + mTopPaddingAdjustment = mClockPositionResult.stackScrollerPaddingAdjustment; } mNotificationStackScroller.setTopPadding(mStackScrollerIntrinsicPadding, mAnimateNextTopPaddingChange || animateClock); @@ -218,28 +215,19 @@ public class NotificationPanelView extends PanelView implements mClockAnimationTarget = -1; } }); - StackStateAnimator.startInstantly(mClockAnimator); + mClockAnimator.start(); return true; } }); } - private int getClockNotificationsPadding(int notificationCount) { - float t = notificationCount - / (mStatusBar.getMaxKeyguardNotifications() + mMoreCardNotificationAmount); - t = Math.min(t, 1.0f); - return (int) (t * mClockNotificationsMarginMin + (1 - t) * mClockNotificationsMarginMax); - } - - private float getClockYFraction(int notificationCount) { - float t = notificationCount - / (mStatusBar.getMaxKeyguardNotifications() + mMoreCardNotificationAmount); - t = Math.min(t, 1.0f); - return (1 - t) * mClockYFractionMax + t * mClockYFractionMin; - } - - private int getClockY(int notificationCount) { - return (int) (getClockYFraction(notificationCount) * getHeight()); + private void applyClockAlpha(float alpha) { + if (alpha != 1.0f) { + mKeyguardStatusView.setLayerType(LAYER_TYPE_HARDWARE, null); + } else { + mKeyguardStatusView.setLayerType(LAYER_TYPE_NONE, null); + } + mKeyguardStatusView.setAlpha(alpha); } public void animateToFullShade() { @@ -366,10 +354,12 @@ public class NotificationPanelView extends PanelView implements @Override public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { - // Block request so we can still intercept the scrolling when QS is expanded. - if (!mQsExpanded) { - super.requestDisallowInterceptTouchEvent(disallowIntercept); + // Block request when interacting with the scroll view so we can still intercept the + // scrolling when QS is expanded. + if (mScrollView.isDispatchingTouchEvent()) { + return; } + super.requestDisallowInterceptTouchEvent(disallowIntercept); } private void flingWithCurrentVelocity() { @@ -466,31 +456,41 @@ public class NotificationPanelView extends PanelView implements setQsExpansion(height); } - private void expandQs() { - mHeader.setExpanded(true); - mNotificationStackScroller.setEnabled(false); - mScrollView.setVisibility(View.VISIBLE); - mQsExpanded = true; + private void setQsExpanded(boolean expanded) { + boolean changed = mQsExpanded != expanded; + if (changed) { + mQsExpanded = expanded; + updateQsState(); + } + } + + public void setKeyguardShowing(boolean keyguardShowing) { + mKeyguardShowing = keyguardShowing; + updateQsState(); } - private void collapseQs() { - mHeader.setExpanded(false); - mNotificationStackScroller.setEnabled(true); - mScrollView.setVisibility(View.INVISIBLE); - mQsExpanded = false; + private void updateQsState() { + mHeader.setExpanded(mQsExpanded); + mNotificationStackScroller.setEnabled(!mQsExpanded); + mQsPanel.setVisibility(mQsExpanded ? View.VISIBLE : View.INVISIBLE); + mQsContainer.setVisibility(mKeyguardShowing && !mQsExpanded + ? View.INVISIBLE + : View.VISIBLE); + mScrollView.setTouchEnabled(mQsExpanded); } private void setQsExpansion(float height) { height = Math.min(Math.max(height, mQsMinExpansionHeight), mQsMaxExpansionHeight); if (height > mQsMinExpansionHeight && !mQsExpanded) { - expandQs(); + setQsExpanded(true); } else if (height <= mQsMinExpansionHeight && mQsExpanded) { - collapseQs(); + setQsExpanded(false); } mQsExpansionHeight = height; - mHeader.setExpansion(height); + mHeader.setExpansion(height - mQsPeekHeight); setQsTranslation(height); setQsStackScrollerPadding(height); + mStatusBar.userActivity(); } private void setQsTranslation(float height) { @@ -626,7 +626,7 @@ public class NotificationPanelView extends PanelView implements int emptyBottomMargin = mStackScrollerContainer.getHeight() - mNotificationStackScroller.getHeight() + mNotificationStackScroller.getEmptyBottomMargin(); - int maxHeight = maxPanelHeight - emptyBottomMargin; + int maxHeight = maxPanelHeight - emptyBottomMargin - mTopPaddingAdjustment; maxHeight = Math.max(maxHeight, mStatusBarMinHeight); return maxHeight; } @@ -637,6 +637,9 @@ public class NotificationPanelView extends PanelView implements @Override protected void onHeightUpdated(float expandedHeight) { + if (!mQsExpanded) { + positionClockAndNotifications(); + } mNotificationStackScroller.setStackHeight(expandedHeight); } @@ -653,6 +656,23 @@ public class NotificationPanelView extends PanelView implements } @Override + protected void onOverExpansionChanged(float overExpansion) { + float currentOverScroll = mNotificationStackScroller.getCurrentOverScrolledPixels(true); + mNotificationStackScroller.setOverScrolledPixels(currentOverScroll + overExpansion + - mOverExpansion, true /* onTop */, false /* animate */); + super.onOverExpansionChanged(overExpansion); + } + + @Override + protected void onTrackingStopped() { + super.onTrackingStopped(); + mOverExpansion = 0.0f; + mNotificationStackScroller.setOverScrolledPixels(0.0f, true /* onTop */, + true /* animate */); + } + + + @Override public void onHeightChanged(ExpandableView view) { requestPanelHeightUpdate(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java index ba0b66e..ea5b309 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone; import android.content.Context; import android.util.AttributeSet; +import android.view.MotionEvent; import android.view.View; import android.widget.ScrollView; @@ -28,6 +29,8 @@ public class ObservableScrollView extends ScrollView { private Listener mListener; private int mLastOverscrollAmount; + private boolean mDispatchingTouchEvent; + private boolean mTouchEnabled = true; public ObservableScrollView(Context context, AttributeSet attrs) { super(context, attrs); @@ -37,10 +40,18 @@ public class ObservableScrollView extends ScrollView { mListener = listener; } + public void setTouchEnabled(boolean touchEnabled) { + mTouchEnabled = touchEnabled; + } + public boolean isScrolledToBottom() { return getScrollY() == getMaxScrollY(); } + public boolean isDispatchingTouchEvent() { + return mDispatchingTouchEvent; + } + private int getMaxScrollY() { int scrollRange = 0; if (getChildCount() > 0) { @@ -52,6 +63,17 @@ public class ObservableScrollView extends ScrollView { } @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (!mTouchEnabled) { + return false; + } + mDispatchingTouchEvent = true; + boolean result = super.dispatchTouchEvent(ev); + mDispatchingTouchEvent = false; + return result; + } + + @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if (mListener != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index b6a43a7..7c1f2cf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -38,6 +38,7 @@ import java.io.PrintWriter; public class PanelView extends FrameLayout { public static final boolean DEBUG = PanelBar.DEBUG; public static final String TAG = PanelView.class.getSimpleName(); + protected float mOverExpansion; private final void logf(String fmt, Object... args) { Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args)); @@ -402,7 +403,12 @@ public class PanelView extends FrameLayout { public void setExpandedHeightInternal(float h) { float fh = getMaxPanelHeight(); - mExpandedHeight = h; + mExpandedHeight = Math.min(fh, h); + float overExpansion = h - fh; + overExpansion = Math.max(0, overExpansion); + if (overExpansion != mOverExpansion) { + onOverExpansionChanged(overExpansion); + } if (DEBUG) { logf("setExpansion: height=%.1f fh=%.1f tracking=%s", h, fh, mTracking ? "T" : "f"); @@ -412,6 +418,10 @@ public class PanelView extends FrameLayout { mExpandedFraction = Math.min(1f, (fh == 0) ? 0 : h / fh); } + protected void onOverExpansionChanged(float overExpansion) { + mOverExpansion = overExpansion; + } + protected void onHeightUpdated(float expandedHeight) { requestLayout(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 54af2c5..28367d0e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -22,6 +22,7 @@ import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; import static android.app.StatusBarManager.windowStateToString; +import static com.android.keyguard.KeyguardHostView.OnDismissAction; import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT; import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE; import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT; @@ -1027,18 +1028,19 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, return new UserHandle(mCurrentUserId); } - public void addNotification(IBinder key, StatusBarNotification notification) { + @Override + public void addNotificationInternal(StatusBarNotification notification) { if (DEBUG) Log.d(TAG, "addNotification score=" + notification.getScore()); - Entry shadeEntry = createNotificationViews(key, notification); + Entry shadeEntry = createNotificationViews(notification); if (shadeEntry == null) { return; } - if (mZenMode != Global.ZEN_MODE_OFF && mIntercepted.tryIntercept(key, notification)) { + if (mZenMode != Global.ZEN_MODE_OFF && mIntercepted.tryIntercept(notification)) { return; } if (mUseHeadsUp && shouldInterrupt(notification)) { if (DEBUG) Log.d(TAG, "launching notification in heads up mode"); - Entry interruptionCandidate = new Entry(key, notification, null); + Entry interruptionCandidate = new Entry(notification, null); ViewGroup holder = mHeadsUpNotificationView.getHolder(); if (inflateViewsForHeadsUp(interruptionCandidate, holder)) { mInterruptingNotificationTime = System.currentTimeMillis(); @@ -1070,7 +1072,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, // show the ticker if there isn't already a heads up if (mInterruptingNotificationEntry == null) { - tick(null, notification, true); + tick(notification, true); } } addNotificationViews(shadeEntry); @@ -1089,12 +1091,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } @Override - public void updateNotification(IBinder key, StatusBarNotification notification) { - super.updateNotification(key, notification); - mIntercepted.update(key, notification); + public void updateNotification(StatusBarNotification notification) { + super.updateNotification(notification); + mIntercepted.update(notification); } - public void removeNotification(IBinder key) { + @Override + public void removeNotificationInternal(String key) { StatusBarNotification old = removeNotificationViews(key); if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old); @@ -2019,7 +2022,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, public void setHardKeyboardStatus(boolean available, boolean enabled) {} @Override - protected void tick(IBinder key, StatusBarNotification n, boolean firstTime) { + protected void tick(StatusBarNotification n, boolean firstTime) { // no ticking in lights-out mode if (!areLightsOn()) return; @@ -2344,6 +2347,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } }; + @Override + protected void startNotificationActivity(OnDismissAction action) { + if (mStatusBarKeyguardViewManager.isShowing()) { + mStatusBarKeyguardViewManager.dismissWithAction(action); + } else { + action.onDismiss(); + } + } + // SystemUIService notifies SystemBars of configuration changes, which then calls down here @Override protected void onConfigurationChanged(Configuration newConfig) { @@ -2758,14 +2770,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { mKeyguardBottomArea.setVisibility(View.VISIBLE); mHeader.setKeyguardShowing(true); + mNotificationPanel.setKeyguardShowing(true); } else { mKeyguardBottomArea.setVisibility(View.GONE); mHeader.setKeyguardShowing(false); + mNotificationPanel.setKeyguardShowing(false); } updateStackScrollerState(); updatePublicMode(); updateRowStates(); + updateSpeedBump(); checkBarModes(); updateNotificationIcons(); updateCarrierLabelVisibility(false); @@ -2776,9 +2791,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } public void userActivity() { - if (mState == StatusBarState.KEYGUARD) { - mKeyguardViewMediatorCallback.userActivity(); - } + mHandler.removeCallbacks(mUserActivity); + mHandler.post(mUserActivity); } public boolean interceptMediaKey(KeyEvent event) { @@ -2936,4 +2950,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, public void onScreenTurnedOn() { mStackScroller.setAnimationsEnabled(true); } + + private final Runnable mUserActivity = new Runnable() { + @Override + public void run() { + if (mState == StatusBarState.KEYGUARD) { + mKeyguardViewMediatorCallback.userActivity(); + } + } + }; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java index 389e725..3245f1a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java @@ -38,6 +38,11 @@ import com.android.systemui.statusbar.policy.UserInfoController; */ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickListener { + /** + * How much the header expansion gets rubberbanded while expanding the panel. + */ + private static final float EXPANSION_RUBBERBAND_FACTOR = 0.35f; + private boolean mExpanded; private boolean mKeyguardShowing; @@ -128,6 +133,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL updateVisibilities(); updateSystemIconsLayoutParams(); updateBrightnessControllerState(); + updateZTranslation(); + updateClickTargets(); if (mQSPanel != null) { mQSPanel.setExpanded(expanded); } @@ -202,18 +209,30 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL } } + private void updateClickTargets() { + mDateTime.setClickable(mExpanded); + mMultiUserSwitch.setClickable(mExpanded); + } + + private void updateZTranslation() { + + // If we are on the Keyguard, we need to set our z position to zero, so we don't get + // shadows. + if (mKeyguardShowing && !mExpanded) { + setZ(0); + } else { + setTranslationZ(0); + } + } + public void setExpansion(float height) { + height = (height - mCollapsedHeight) * EXPANSION_RUBBERBAND_FACTOR + mCollapsedHeight; if (height < mCollapsedHeight) { height = mCollapsedHeight; } if (height > mExpandedHeight) { height = mExpandedHeight; } - if (mExpanded) { - mBackground.setTranslationY(-(mExpandedHeight - height)); - } else { - mBackground.setTranslationY(0); - } setClipping(height); } @@ -247,14 +266,10 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL public void setKeyguardShowing(boolean keyguardShowing) { mKeyguardShowing = keyguardShowing; - if (keyguardShowing) { - setZ(0); - } else { - setTranslationZ(0); - } updateHeights(); updateWidth(); updateVisibilities(); + updateZTranslation(); } public void setUserInfoController(UserInfoController userInfoController) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 1040c15..3849d8d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -29,6 +29,8 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; +import static com.android.keyguard.KeyguardHostView.OnDismissAction; + /** * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back * via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done, @@ -108,6 +110,13 @@ public class StatusBarKeyguardViewManager { updateStates(); } + public void dismissWithAction(OnDismissAction r) { + if (!mOccluded) { + mBouncer.showWithDismissAction(r); + } + updateStates(); + } + /** * Reset the state of the view. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java index 173af40..3ce6905 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java @@ -166,7 +166,7 @@ public final class UserInfoController { if (rawAvatar != null) { avatar = new BitmapDrawable(mContext.getResources(), circularClip(rawAvatar)); } else { - avatar = mContext.getResources().getDrawable(R.drawable.ic_qs_default_user); + avatar = mContext.getResources().getDrawable(R.drawable.ic_account_circle); mUseDefaultAvatar = true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java index 41914ed..5e2d06b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java @@ -28,6 +28,7 @@ public class AnimationFilter { boolean animateScale; boolean animateHeight; boolean animateDimmed; + boolean hasDelays; public AnimationFilter animateAlpha() { animateAlpha = true; @@ -39,6 +40,11 @@ public class AnimationFilter { return this; } + public AnimationFilter hasDelays() { + hasDelays = true; + return this; + } + public AnimationFilter animateZ() { animateZ = true; return this; @@ -79,6 +85,7 @@ public class AnimationFilter { animateScale |= filter.animateScale; animateHeight |= filter.animateHeight; animateDimmed |= filter.animateDimmed; + hasDelays |= filter.hasDelays; } private void reset() { @@ -88,5 +95,6 @@ public class AnimationFilter { animateScale = false; animateHeight = false; animateDimmed = false; + hasDelays = false; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 90f3d17..079b184 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -103,6 +103,7 @@ public class NotificationStackScrollLayout extends ViewGroup private ArrayList<View> mChildrenToRemoveAnimated = new ArrayList<View>(); private ArrayList<View> mSnappedBackChildren = new ArrayList<View>(); private ArrayList<View> mDragAnimPendingChildren = new ArrayList<View>(); + private ArrayList<View> mChildrenChangingPositions = new ArrayList<View>(); private ArrayList<AnimationEvent> mAnimationEvents = new ArrayList<AnimationEvent>(); private ArrayList<View> mSwipedOutViews = new ArrayList<View>(); @@ -969,9 +970,24 @@ public class NotificationStackScrollLayout extends ViewGroup } /** + * @return The first child which has visibility unequal to GONE which is currently below the + * given translationY or equal to it. + */ + private View getFirstChildBelowTranlsationY(float translationY) { + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = getChildAt(i); + if (child.getVisibility() != View.GONE && child.getTranslationY() >= translationY) { + return child; + } + } + return null; + } + + /** * @return the last child which has visibility unequal to GONE */ - private View getLastChildNotGone() { + public View getLastChildNotGone() { int childCount = getChildCount(); for (int i = childCount - 1; i >= 0; i--) { View child = getChildAt(i); @@ -1094,23 +1110,41 @@ public class NotificationStackScrollLayout extends ViewGroup @Override protected void onViewRemoved(View child) { super.onViewRemoved(child); + mStackScrollAlgorithm.notifyChildrenChanged(this); + if (mChildrenChangingPositions.contains(child)) { + // This is only a position change, don't do anything special + return; + } ((ExpandableView) child).setOnHeightChangedListener(null); mCurrentStackScrollState.removeViewStateForView(child); - mStackScrollAlgorithm.notifyChildrenChanged(this); updateScrollStateForRemovedChild(child); - generateRemoveAnimation(child); + boolean animationGenerated = generateRemoveAnimation(child); + if (animationGenerated && !mSwipedOutViews.contains(child)) { + // Add this view to an overlay in order to ensure that it will still be temporary + // drawn when removed + getOverlay().add(child); + } } - private void generateRemoveAnimation(View child) { + /** + * Generate a remove animation for a child view. + * + * @param child The view to generate the remove animation for. + * @return Whether an animation was generated. + */ + private boolean generateRemoveAnimation(View child) { if (mIsExpanded && mAnimationsEnabled) { if (!mChildrenToAddAnimated.contains(child)) { // Generate Animations mChildrenToRemoveAnimated.add(child); mNeedsAnimation = true; + return true; } else { mChildrenToAddAnimated.remove(child); + return false; } } + return false; } /** @@ -1155,9 +1189,7 @@ public class NotificationStackScrollLayout extends ViewGroup super.onViewAdded(child); mStackScrollAlgorithm.notifyChildrenChanged(this); ((ExpandableView) child).setOnHeightChangedListener(this); - if (child.getVisibility() != View.GONE) { - generateAddAnimation(child); - } + generateAddAnimation(child); } public void setAnimationsEnabled(boolean animationsEnabled) { @@ -1168,10 +1200,13 @@ public class NotificationStackScrollLayout extends ViewGroup return mNeedsAnimation && (!mChildrenToAddAnimated.isEmpty() || !mChildrenToRemoveAnimated.isEmpty()); } - + /** + * Generate an animation for an added child view. + * + * @param child The view to be added. + */ public void generateAddAnimation(View child) { - if (mIsExpanded && mAnimationsEnabled) { - + if (mIsExpanded && mAnimationsEnabled && !mChildrenChangingPositions.contains(child)) { // Generate Animations mChildrenToAddAnimated.add(child); mNeedsAnimation = true; @@ -1186,9 +1221,10 @@ public class NotificationStackScrollLayout extends ViewGroup */ public void changeViewPosition(View child, int newIndex) { if (child != null && child.getParent() == this) { + mChildrenChangingPositions.add(child); removeView(child); addView(child, newIndex); - // TODO: handle events + mNeedsAnimation = true; } } @@ -1197,16 +1233,18 @@ public class NotificationStackScrollLayout extends ViewGroup generateChildHierarchyEvents(); mNeedsAnimation = false; } - if (!mAnimationEvents.isEmpty()) { + if (!mAnimationEvents.isEmpty() || isCurrentlyAnimating()) { mStateAnimator.startAnimationForEvents(mAnimationEvents, mCurrentStackScrollState); + mAnimationEvents.clear(); } else { applyCurrentState(); } } private void generateChildHierarchyEvents() { - generateChildAdditionEvents(); generateChildRemovalEvents(); + generateChildAdditionEvents(); + generatePositionChangeEvents(); generateSnapBackEvents(); generateDragEvents(); generateTopPaddingEvent(); @@ -1237,12 +1275,24 @@ public class NotificationStackScrollLayout extends ViewGroup int animationType = childWasSwipedOut ? AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT : AnimationEvent.ANIMATION_TYPE_REMOVE; - mAnimationEvents.add(new AnimationEvent(child, animationType)); + AnimationEvent event = new AnimationEvent(child, animationType); + + // we need to know the view after this one + event.viewAfterChangingView = getFirstChildBelowTranlsationY(child.getTranslationY()); + mAnimationEvents.add(event); } mSwipedOutViews.clear(); mChildrenToRemoveAnimated.clear(); } + private void generatePositionChangeEvents() { + for (View child : mChildrenChangingPositions) { + mAnimationEvents.add(new AnimationEvent(child, + AnimationEvent.ANIMATION_TYPE_CHANGE_POSITION)); + } + mChildrenChangingPositions.clear(); + } + private void generateChildAdditionEvents() { for (View child : mChildrenToAddAnimated) { mAnimationEvents.add(new AnimationEvent(child, @@ -1467,7 +1517,6 @@ public class NotificationStackScrollLayout extends ViewGroup public void onChildAnimationFinished() { requestChildrenUpdate(); - mAnimationEvents.clear(); } /** @@ -1513,9 +1562,9 @@ public class NotificationStackScrollLayout extends ViewGroup } private void updateSpeedBump(boolean visible) { - int newVisibility = visible ? VISIBLE : GONE; - int oldVisibility = mSpeedBumpView.getVisibility(); - if (newVisibility != oldVisibility) { + boolean notGoneBefore = mSpeedBumpView.getVisibility() != GONE; + if (visible != notGoneBefore) { + int newVisibility = visible ? VISIBLE : GONE; mSpeedBumpView.setVisibility(newVisibility); if (visible) { mSpeedBumpView.collapse(); @@ -1551,21 +1600,24 @@ public class NotificationStackScrollLayout extends ViewGroup .animateAlpha() .animateHeight() .animateY() - .animateZ(), + .animateZ() + .hasDelays(), // ANIMATION_TYPE_REMOVE new AnimationFilter() .animateAlpha() .animateHeight() .animateY() - .animateZ(), + .animateZ() + .hasDelays(), // ANIMATION_TYPE_REMOVE_SWIPED_OUT new AnimationFilter() .animateAlpha() .animateHeight() .animateY() - .animateZ(), + .animateZ() + .hasDelays(), // ANIMATION_TYPE_TOP_PADDING_CHANGED new AnimationFilter() @@ -1593,16 +1645,23 @@ public class NotificationStackScrollLayout extends ViewGroup new AnimationFilter() .animateY() .animateScale() - .animateDimmed() + .animateDimmed(), + + // ANIMATION_TYPE_CHANGE_POSITION + new AnimationFilter() + .animateAlpha() + .animateHeight() + .animateY() + .animateZ() }; static int[] LENGTHS = new int[] { // ANIMATION_TYPE_ADD - StackStateAnimator.ANIMATION_DURATION_STANDARD, + StackStateAnimator.ANIMATION_DURATION_APPEAR_DISAPPEAR, // ANIMATION_TYPE_REMOVE - StackStateAnimator.ANIMATION_DURATION_STANDARD, + StackStateAnimator.ANIMATION_DURATION_APPEAR_DISAPPEAR, // ANIMATION_TYPE_REMOVE_SWIPED_OUT StackStateAnimator.ANIMATION_DURATION_STANDARD, @@ -1621,22 +1680,27 @@ public class NotificationStackScrollLayout extends ViewGroup // ANIMATION_TYPE_DIMMED StackStateAnimator.ANIMATION_DURATION_DIMMED_ACTIVATED, + + // ANIMATION_TYPE_CHANGE_POSITION + StackStateAnimator.ANIMATION_DURATION_STANDARD, }; - static int ANIMATION_TYPE_ADD = 0; - static int ANIMATION_TYPE_REMOVE = 1; - static int ANIMATION_TYPE_REMOVE_SWIPED_OUT = 2; - static int ANIMATION_TYPE_TOP_PADDING_CHANGED = 3; - static int ANIMATION_TYPE_START_DRAG = 4; - static int ANIMATION_TYPE_SNAP_BACK = 5; - static int ANIMATION_TYPE_ACTIVATED_CHILD = 6; - static int ANIMATION_TYPE_DIMMED = 7; + static final int ANIMATION_TYPE_ADD = 0; + static final int ANIMATION_TYPE_REMOVE = 1; + static final int ANIMATION_TYPE_REMOVE_SWIPED_OUT = 2; + static final int ANIMATION_TYPE_TOP_PADDING_CHANGED = 3; + static final int ANIMATION_TYPE_START_DRAG = 4; + static final int ANIMATION_TYPE_SNAP_BACK = 5; + static final int ANIMATION_TYPE_ACTIVATED_CHILD = 6; + static final int ANIMATION_TYPE_DIMMED = 7; + static final int ANIMATION_TYPE_CHANGE_POSITION = 8; final long eventStartTime; final View changingView; final int animationType; final AnimationFilter filter; final long length; + View viewAfterChangingView; AnimationEvent(View view, int type) { eventStartTime = AnimationUtils.currentAnimationTimeMillis(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java index d572ea5..bd2541a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java @@ -208,6 +208,8 @@ public class StackScrollAlgorithm { for (int i = 0; i < childCount; i++) { ExpandableView v = (ExpandableView) hostView.getChildAt(i); if (v.getVisibility() != View.GONE) { + StackScrollState.ViewState viewState = resultState.getViewStateForView(v); + viewState.notGoneIndex = state.visibleChildren.size(); state.visibleChildren.add(v); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java index 011411c..44e10be 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java @@ -37,15 +37,14 @@ public class StackScrollState { private static final String CHILD_NOT_FOUND_TAG = "StackScrollStateNoSuchChild"; private final ViewGroup mHostView; + private final int mRoundedRectCornerRadius; private Map<ExpandableView, ViewState> mStateMap; private final Rect mClipRect = new Rect(); - private int mBackgroundRoundedRectCornerRadius; - private final Outline mChildOutline = new Outline(); public StackScrollState(ViewGroup hostView) { mHostView = hostView; mStateMap = new HashMap<ExpandableView, ViewState>(); - mBackgroundRoundedRectCornerRadius = hostView.getResources().getDimensionPixelSize( + mRoundedRectCornerRadius = mHostView.getResources().getDimensionPixelSize( com.android.internal.R.dimen.notification_quantum_rounded_rect_radius); } @@ -66,6 +65,7 @@ public class StackScrollState { viewState.height = child.getIntrinsicHeight(); viewState.gone = child.getVisibility() == View.GONE; viewState.alpha = 1; + viewState.notGoneIndex = -1; } } @@ -158,11 +158,15 @@ public class StackScrollState { // apply clipping and shadow float newNotificationEnd = newYTranslation + newHeight; + // In the unlocked shade we have to clip a little bit higher because of the rounded + // corners of the notifications. + float clippingCorrection = state.dimmed ? 0 : mRoundedRectCornerRadius; + // When the previous notification is swiped, we don't clip the content to the // bottom of it. float clipHeight = previousNotificationIsSwiped ? newHeight - : newNotificationEnd - (previousNotificationEnd); + : newNotificationEnd - (previousNotificationEnd - clippingCorrection); updateChildClippingAndBackground(child, newHeight, clipHeight, @@ -190,7 +194,7 @@ public class StackScrollState { if (nextChild != null) { ViewState nextState = getViewStateForView(nextChild); boolean startIsAboveNext = nextState.yTranslation > speedBumpStart; - speedBump.animateDivider(startIsAboveNext); + speedBump.animateDivider(startIsAboveNext, null /* onFinishedRunnable */); // handle expanded case if (speedBump.isExpanded()) { @@ -272,6 +276,11 @@ public class StackScrollState { boolean dimmed; /** + * The index of the view, only accounting for views not equal to GONE + */ + int notGoneIndex; + + /** * The location this view is currently rendered at. * * <p>See <code>LOCATION_</code> flags.</p> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java index a9dcdd6..f019e6c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java @@ -39,7 +39,11 @@ import java.util.Stack; public class StackStateAnimator { public static final int ANIMATION_DURATION_STANDARD = 360; + public static final int ANIMATION_DURATION_APPEAR_DISAPPEAR = 464; public static final int ANIMATION_DURATION_DIMMED_ACTIVATED = 220; + public static final int ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING = 80; + public static final int ANIMATION_DELAY_PER_ELEMENT_MANUAL = 32; + private static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE = 2; private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag; private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag; @@ -62,10 +66,9 @@ public class StackStateAnimator { private final Interpolator mFastOutSlowInInterpolator; public NotificationStackScrollLayout mHostLayout; - private ArrayList<NotificationStackScrollLayout.AnimationEvent> mHandledEvents = - new ArrayList<>(); private ArrayList<NotificationStackScrollLayout.AnimationEvent> mNewEvents = new ArrayList<>(); + private ArrayList<View> mNewAddChildren = new ArrayList<>(); private Set<Animator> mAnimatorSet = new HashSet<Animator>(); private Stack<AnimatorListenerAdapter> mAnimationListenerPool = new Stack<AnimatorListenerAdapter>(); @@ -96,57 +99,130 @@ public class StackStateAnimator { mCurrentLength = NotificationStackScrollLayout.AnimationEvent.combineLength(mNewEvents); for (int i = 0; i < childCount; i++) { final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i); + StackScrollState.ViewState viewState = finalState.getViewStateForView(child); - if (viewState == null) { + if (viewState == null || child.getVisibility() == View.GONE) { continue; } - startAnimations(child, viewState); - child.setClipBounds(null); + startAnimations(child, viewState, finalState); } if (!isRunning()) { // no child has preformed any animation, lets finish onAnimationFinished(); } + mNewEvents.clear(); + mNewAddChildren.clear(); } /** * Start an animation to the given viewState */ - private void startAnimations(final ExpandableView child, StackScrollState.ViewState viewState) { + private void startAnimations(final ExpandableView child, StackScrollState.ViewState viewState, + StackScrollState finalState) { int childVisibility = child.getVisibility(); boolean wasVisible = childVisibility == View.VISIBLE; final float alpha = viewState.alpha; if (!wasVisible && alpha != 0 && !viewState.gone) { child.setVisibility(View.VISIBLE); } + + boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation; + boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation; + boolean scaleChanging = child.getScaleX() != viewState.scale; + boolean alphaChanging = alpha != child.getAlpha(); + boolean heightChanging = viewState.height != child.getActualHeight(); + boolean wasAdded = mNewAddChildren.contains(child); + boolean hasDelays = mAnimationFilter.hasDelays; + boolean isDelayRelevant = yTranslationChanging || zTranslationChanging || scaleChanging || + alphaChanging || heightChanging; + long delay = 0; + if (hasDelays && isDelayRelevant || wasAdded) { + delay = calculateChildAnimationDelay(viewState, finalState); + } + // start translationY animation - if (child.getTranslationY() != viewState.yTranslation) { - startYTranslationAnimation(child, viewState); + if (yTranslationChanging) { + startYTranslationAnimation(child, viewState, delay); } + // start translationZ animation - if (child.getTranslationZ() != viewState.zTranslation) { - startZTranslationAnimation(child, viewState); + if (zTranslationChanging) { + startZTranslationAnimation(child, viewState, delay); } + // start scale animation - if (child.getScaleX() != viewState.scale) { + if (scaleChanging) { startScaleAnimation(child, viewState); } + // start alpha animation - if (alpha != child.getAlpha()) { - startAlphaAnimation(child, viewState); + if (alphaChanging) { + startAlphaAnimation(child, viewState, delay); } + // start height animation - if (viewState.height != child.getActualHeight()) { - startHeightAnimation(child, viewState); + if (heightChanging) { + startHeightAnimation(child, viewState, delay); } + // start dimmed animation child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed); + + if (wasAdded) { + child.performAddAnimation(delay); + } + } + + private long calculateChildAnimationDelay(StackScrollState.ViewState viewState, + StackScrollState finalState) { + long minDelay = 0; + for (NotificationStackScrollLayout.AnimationEvent event : mNewEvents) { + long delayPerElement = ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING; + switch (event.animationType) { + case NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD: { + int ownIndex = viewState.notGoneIndex; + int changingIndex = finalState + .getViewStateForView(event.changingView).notGoneIndex; + int difference = Math.abs(ownIndex - changingIndex); + difference = Math.max(0, Math.min(DELAY_EFFECT_MAX_INDEX_DIFFERENCE, + difference - 1)); + long delay = (DELAY_EFFECT_MAX_INDEX_DIFFERENCE - difference) * delayPerElement; + minDelay = Math.max(delay, minDelay); + break; + } + case NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT: + delayPerElement = ANIMATION_DELAY_PER_ELEMENT_MANUAL; + case NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE: { + int ownIndex = viewState.notGoneIndex; + boolean noNextView = event.viewAfterChangingView == null; + View viewAfterChangingView = noNextView + ? mHostLayout.getLastChildNotGone() + : event.viewAfterChangingView; + + int nextIndex = finalState + .getViewStateForView(viewAfterChangingView).notGoneIndex; + if (ownIndex >= nextIndex) { + // we only have the view afterwards + ownIndex++; + } + int difference = Math.abs(ownIndex - nextIndex); + difference = Math.max(0, Math.min(DELAY_EFFECT_MAX_INDEX_DIFFERENCE, + difference - 1)); + long delay = difference * delayPerElement; + minDelay = Math.max(delay, minDelay); + break; + } + default: + break; + } + } + return minDelay; } private void startHeightAnimation(final ExpandableView child, - StackScrollState.ViewState viewState) { + StackScrollState.ViewState viewState, long delay) { Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT); Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT); int newEndValue = viewState.height; @@ -185,6 +261,9 @@ public class StackStateAnimator { animator.setInterpolator(mFastOutSlowInInterpolator); long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator); animator.setDuration(newDuration); + if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) { + animator.setStartDelay(delay); + } animator.addListener(getGlobalAnimationFinishedListener()); // remove the tag when the animation is finished animator.addListener(new AnimatorListenerAdapter() { @@ -195,14 +274,14 @@ public class StackStateAnimator { child.setTag(TAG_END_HEIGHT, null); } }); - startInstantly(animator); + startAnimator(animator); child.setTag(TAG_ANIMATOR_HEIGHT, animator); child.setTag(TAG_START_HEIGHT, child.getActualHeight()); child.setTag(TAG_END_HEIGHT, newEndValue); } private void startAlphaAnimation(final ExpandableView child, - final StackScrollState.ViewState viewState) { + final StackScrollState.ViewState viewState, long delay) { Float previousStartValue = getChildTag(child,TAG_START_ALPHA); Float previousEndValue = getChildTag(child,TAG_END_ALPHA); final float newEndValue = viewState.alpha; @@ -236,14 +315,13 @@ public class StackStateAnimator { child.getAlpha(), newEndValue); animator.setInterpolator(mFastOutSlowInInterpolator); // Handle layer type - final int currentLayerType = child.getLayerType(); child.setLayerType(View.LAYER_TYPE_HARDWARE, null); animator.addListener(new AnimatorListenerAdapter() { public boolean mWasCancelled; @Override public void onAnimationEnd(Animator animation) { - child.setLayerType(currentLayerType, null); + child.setLayerType(View.LAYER_TYPE_NONE, null); if (newEndValue == 0 && !mWasCancelled) { child.setVisibility(View.INVISIBLE); } @@ -264,6 +342,9 @@ public class StackStateAnimator { }); long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator); animator.setDuration(newDuration); + if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) { + animator.setStartDelay(delay); + } animator.addListener(getGlobalAnimationFinishedListener()); // remove the tag when the animation is finished animator.addListener(new AnimatorListenerAdapter() { @@ -272,14 +353,14 @@ public class StackStateAnimator { } }); - startInstantly(animator); + startAnimator(animator); child.setTag(TAG_ANIMATOR_ALPHA, animator); child.setTag(TAG_START_ALPHA, child.getAlpha()); child.setTag(TAG_END_ALPHA, newEndValue); } private void startZTranslationAnimation(final ExpandableView child, - final StackScrollState.ViewState viewState) { + final StackScrollState.ViewState viewState, long delay) { Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z); Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z); float newEndValue = viewState.zTranslation; @@ -311,6 +392,9 @@ public class StackStateAnimator { animator.setInterpolator(mFastOutSlowInInterpolator); long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator); animator.setDuration(newDuration); + if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) { + animator.setStartDelay(delay); + } animator.addListener(getGlobalAnimationFinishedListener()); // remove the tag when the animation is finished animator.addListener(new AnimatorListenerAdapter() { @@ -321,14 +405,14 @@ public class StackStateAnimator { child.setTag(TAG_END_TRANSLATION_Z, null); } }); - startInstantly(animator); + startAnimator(animator); child.setTag(TAG_ANIMATOR_TRANSLATION_Z, animator); child.setTag(TAG_START_TRANSLATION_Z, child.getTranslationZ()); child.setTag(TAG_END_TRANSLATION_Z, newEndValue); } private void startYTranslationAnimation(final ExpandableView child, - StackScrollState.ViewState viewState) { + StackScrollState.ViewState viewState, long delay) { Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y); Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y); float newEndValue = viewState.yTranslation; @@ -361,6 +445,9 @@ public class StackStateAnimator { animator.setInterpolator(mFastOutSlowInInterpolator); long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator); animator.setDuration(newDuration); + if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) { + animator.setStartDelay(delay); + } animator.addListener(getGlobalAnimationFinishedListener()); // remove the tag when the animation is finished animator.addListener(new AnimatorListenerAdapter() { @@ -371,7 +458,7 @@ public class StackStateAnimator { child.setTag(TAG_END_TRANSLATION_Y, null); } }); - startInstantly(animator); + startAnimator(animator); child.setTag(TAG_ANIMATOR_TRANSLATION_Y, animator); child.setTag(TAG_START_TRANSLATION_Y, child.getTranslationY()); child.setTag(TAG_END_TRANSLATION_Y, newEndValue); @@ -425,18 +512,15 @@ public class StackStateAnimator { child.setTag(TAG_END_SCALE, null); } }); - startInstantly(animator); + startAnimator(animator); child.setTag(TAG_ANIMATOR_SCALE, animator); child.setTag(TAG_START_SCALE, child.getScaleX()); child.setTag(TAG_END_SCALE, newEndValue); } - /** - * Start an animator instantly instead of waiting on the next synchronization frame - */ - public static void startInstantly(ValueAnimator animator) { + private void startAnimator(ValueAnimator animator) { + mAnimatorSet.add(animator); animator.start(); - animator.setCurrentPlayTime(0); } /** @@ -468,7 +552,6 @@ public class StackStateAnimator { @Override public void onAnimationStart(Animator animation) { - mAnimatorSet.add(animation); mWasCancelled = false; } }; @@ -497,8 +580,6 @@ public class StackStateAnimator { } private void onAnimationFinished() { - mHandledEvents.clear(); - mNewEvents.clear(); mHostLayout.onChildAnimationFinished(); } @@ -511,27 +592,60 @@ public class StackStateAnimator { private void processAnimationEvents( ArrayList<NotificationStackScrollLayout.AnimationEvent> animationEvents, StackScrollState finalState) { - mNewEvents.clear(); for (NotificationStackScrollLayout.AnimationEvent event : animationEvents) { - View changingView = event.changingView; - if (!mHandledEvents.contains(event)) { - if (event.animationType == NotificationStackScrollLayout.AnimationEvent - .ANIMATION_TYPE_ADD) { - - // This item is added, initialize it's properties. - StackScrollState.ViewState viewState = finalState - .getViewStateForView(changingView); - if (viewState == null) { - // The position for this child was never generated, let's continue. - continue; - } - changingView.setAlpha(0); - changingView.setTranslationY(viewState.yTranslation); - changingView.setTranslationZ(viewState.zTranslation); + final ExpandableView changingView = (ExpandableView) event.changingView; + if (event.animationType == + NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD) { + + // This item is added, initialize it's properties. + StackScrollState.ViewState viewState = finalState + .getViewStateForView(changingView); + if (viewState == null) { + // The position for this child was never generated, let's continue. + continue; + } + if (changingView.getVisibility() == View.GONE) { + // The view was set to gone but the state never removed + finalState.removeViewStateForView(changingView); + continue; } - mHandledEvents.add(event); - mNewEvents.add(event); + changingView.setAlpha(viewState.alpha); + changingView.setTranslationY(viewState.yTranslation); + changingView.setTranslationZ(viewState.zTranslation); + changingView.setActualHeight(viewState.height, false); + mNewAddChildren.add(changingView); + + } else if (event.animationType == + NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE) { + if (changingView.getVisibility() == View.GONE) { + continue; + } + + // Find the amount to translate up. This is needed in order to understand the + // direction of the remove animation (either downwards or upwards) + StackScrollState.ViewState viewState = finalState + .getViewStateForView(event.viewAfterChangingView); + int actualHeight = changingView.getActualHeight(); + // upwards by default + float translationDirection = -1.0f; + if (viewState != null) { + // there was a view after this one, Approximate the distance the next child + // travelled + translationDirection = ((viewState.yTranslation + - (changingView.getTranslationY() + actualHeight / 2.0f)) * 2 / + actualHeight); + translationDirection = Math.max(Math.min(translationDirection, 1.0f),-1.0f); + + } + changingView.performRemoveAnimation(translationDirection, new Runnable() { + @Override + public void run() { + // remove the temporary overlay + mHostLayout.getOverlay().remove(changingView); + } + }); } + mNewEvents.add(event); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java index 9006c9a..25147b4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java @@ -46,15 +46,23 @@ public class TvStatusBar extends BaseStatusBar { } @Override - public void addNotification(IBinder key, StatusBarNotification notification) { + public void addNotification(StatusBarNotification notification) { } @Override - public void updateNotification(IBinder key, StatusBarNotification notification) { + public void addNotificationInternal(StatusBarNotification notification) { } @Override - public void removeNotification(IBinder key) { + public void updateNotification(StatusBarNotification notification) { + } + + @Override + protected void removeNotificationInternal(String key) { + } + + @Override + public void removeNotification(String key) { } @Override @@ -113,7 +121,7 @@ public class TvStatusBar extends BaseStatusBar { } @Override - protected void tick(IBinder key, StatusBarNotification n, boolean firstTime) { + protected void tick(StatusBarNotification n, boolean firstTime) { } @Override diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 9977193..e178773 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -478,6 +478,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private static final int MSG_DISABLE_POINTER_LOCATION = 2; private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3; private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4; + private static final int MSG_DISPATCH_SHOW_RECENTS = 5; private class PolicyHandler extends Handler { @Override @@ -495,6 +496,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { case MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK: dispatchMediaKeyRepeatWithWakeLock((KeyEvent)msg.obj); break; + case MSG_DISPATCH_SHOW_RECENTS: + showRecentApps(false); + break; } } } @@ -2459,6 +2463,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + @Override + public void showRecentApps() { + mHandler.removeMessages(MSG_DISPATCH_SHOW_RECENTS); + mHandler.sendEmptyMessage(MSG_DISPATCH_SHOW_RECENTS); + } + private void showRecentApps(boolean triggeredFromAltTab) { mPreloadedRecentApps = false; // preloading no longer needs to be canceled try { diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 0ad5ce2..7ecf248 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -5750,10 +5750,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { // updateNetworkSettings(); } // notify battery stats service about this network -// try { - // TODO - //BatteryStatsService.getService().noteNetworkInterfaceType(iface, netType); -// } catch (RemoteException e) { } + try { + BatteryStatsService.getService().noteNetworkInterfaceType( + newNetwork.linkProperties.getInterfaceName(), + newNetwork.networkInfo.getType()); + } catch (RemoteException e) { } notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_AVAILABLE); } else { if (DBG && newNetwork.networkRequests.size() != 0) { diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java index 0d2cee8..5cfc49c 100644 --- a/services/core/java/com/android/server/LockSettingsService.java +++ b/services/core/java/com/android/server/LockSettingsService.java @@ -47,12 +47,14 @@ import android.util.Log; import android.util.Slog; import com.android.internal.widget.ILockSettings; +import com.android.internal.widget.ILockSettingsObserver; import com.android.internal.widget.LockPatternUtils; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -65,6 +67,9 @@ import java.util.List; public class LockSettingsService extends ILockSettings.Stub { private static final String PERMISSION = "android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"; + + private static final String SYSTEM_DEBUGGABLE = "ro.debuggable"; + private final DatabaseHelper mOpenHelper; private static final String TAG = "LockSettingsService"; @@ -85,6 +90,8 @@ public class LockSettingsService extends ILockSettings.Stub { private LockPatternUtils mLockPatternUtils; private boolean mFirstCallToVold; + private final ArrayList<LockSettingsObserver> mObservers = new ArrayList<>(); + public LockSettingsService(Context context) { mContext = context; // Open the database @@ -222,6 +229,52 @@ public class LockSettingsService extends ILockSettings.Stub { return readFromDb(key, defaultValue, userId); } + @Override + public void registerObserver(ILockSettingsObserver remote) throws RemoteException { + synchronized (mObservers) { + for (int i = 0; i < mObservers.size(); i++) { + if (mObservers.get(i).remote.asBinder() == remote.asBinder()) { + boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")); + if (isDebuggable) { + throw new IllegalStateException("Observer was already registered."); + } else { + Log.e(TAG, "Observer was already registered."); + return; + } + } + } + LockSettingsObserver o = new LockSettingsObserver(); + o.remote = remote; + o.remote.asBinder().linkToDeath(o, 0); + mObservers.add(o); + } + } + + @Override + public void unregisterObserver(ILockSettingsObserver remote) throws RemoteException { + synchronized (mObservers) { + for (int i = 0; i < mObservers.size(); i++) { + if (mObservers.get(i).remote.asBinder() == remote.asBinder()) { + mObservers.remove(i); + return; + } + } + } + } + + public void notifyObservers(String key, int userId) { + synchronized (mObservers) { + for (int i = 0; i < mObservers.size(); i++) { + try { + mObservers.get(i).remote.onLockSettingChanged(key, userId); + } catch (RemoteException e) { + // The stack trace is not really helpful here. + Log.e(TAG, "Failed to notify ILockSettingsObserver: " + e); + } + } + } + } + private String getLockPatternFilename(int userId) { String dataSystemDirectory = android.os.Environment.getDataDirectory().getAbsolutePath() + @@ -438,6 +491,7 @@ public class LockSettingsService extends ILockSettings.Stub { private void writeToDb(String key, String value, int userId) { writeToDb(mOpenHelper.getWritableDatabase(), key, value, userId); + notifyObservers(key, userId); } private void writeToDb(SQLiteDatabase db, String key, String value, int userId) { @@ -583,4 +637,13 @@ public class LockSettingsService extends ILockSettings.Stub { } return null; } + + private class LockSettingsObserver implements DeathRecipient { + ILockSettingsObserver remote; + + @Override + public void binderDied() { + mObservers.remove(this); + } + } } diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index cf91782..137387e 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -240,9 +240,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub mPhoneStateListener = new PhoneStateListener(mDaemonHandler.getLooper()) { public void onDataConnectionRealTimeInfoChanged( DataConnectionRealTimeInfo dcRtInfo) { - // Disabled for now, until we are getting good data. - //notifyInterfaceClassActivity(ConnectivityManager.TYPE_MOBILE, - // dcRtInfo.getDcPowerState(), dcRtInfo.getTime(), true); + notifyInterfaceClassActivity(ConnectivityManager.TYPE_MOBILE, + dcRtInfo.getDcPowerState(), dcRtInfo.getTime(), true); } }; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ac30319..88bebcb 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -409,7 +409,7 @@ public final class ActivityManagerService extends ActivityManagerNative /** * List of intents that were used to start the most recent tasks. */ - final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>(); + ArrayList<TaskRecord> mRecentTasks; public class PendingAssistExtras extends Binder implements Runnable { public final ActivityRecord activity; @@ -822,6 +822,11 @@ public final class ActivityManagerService extends ActivityManagerNative final AppOpsService mAppOpsService; /** + * Save recent tasks information across reboots. + */ + final TaskPersister mTaskPersister; + + /** * Current configuration information. HistoryRecord objects are given * a reference to this object to indicate which configuration they are * currently running in, so this object must be kept immutable. @@ -2138,6 +2143,7 @@ public final class ActivityManagerService extends ActivityManagerNative mCompatModePackages = new CompatModePackages(this, systemDir, mHandler); mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler); mStackSupervisor = new ActivityStackSupervisor(this); + mTaskPersister = new TaskPersister(systemDir, mStackSupervisor); mProcessCpuThread = new Thread("CpuTracker") { @Override @@ -7081,12 +7087,12 @@ public final class ActivityManagerService extends ActivityManagerNative private ActivityManager.RecentTaskInfo createRecentTaskInfoFromTaskRecord(TaskRecord tr) { ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo(); - rti.id = tr.numActivities > 0 ? tr.taskId : -1; + rti.id = tr.mActivities.isEmpty() ? -1 : tr.taskId; rti.persistentId = tr.taskId; rti.baseIntent = new Intent(tr.getBaseIntent()); rti.origActivity = tr.origActivity; rti.description = tr.lastDescription; - rti.stackId = tr.stack.mStackId; + rti.stackId = tr.stack != null ? tr.stack.mStackId : -1; rti.userId = tr.userId; rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription); return rti; @@ -7320,6 +7326,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (tr != null) { tr.removeTaskActivitiesLocked(-1, false); cleanUpRemovedTaskLocked(tr, flags); + if (tr.isPersistable) { + notifyTaskPersisterLocked(tr, true); + } return true; } return false; @@ -7559,14 +7568,11 @@ public final class ActivityManagerService extends ActivityManagerNative try { synchronized (this) { TaskRecord tr = recentTaskForIdLocked(taskId); - if (tr != null) { - return tr.stack.isHomeStack(); - } + return tr != null && tr.stack != null && tr.stack.isHomeStack(); } } finally { Binder.restoreCallingIdentity(ident); } - return false; } @Override @@ -8635,6 +8641,10 @@ public final class ActivityManagerService extends ActivityManagerNative } } + void notifyTaskPersisterLocked(TaskRecord task, boolean flush) { + mTaskPersister.notify(task, flush); + } + @Override public boolean shutdown(int timeout) { if (checkCallingPermission(android.Manifest.permission.SHUTDOWN) @@ -8657,6 +8667,7 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized (this) { mProcessStats.shutdownLocked(); } + notifyTaskPersisterLocked(null, true); return timedout; } @@ -9562,7 +9573,13 @@ public final class ActivityManagerService extends ActivityManagerNative if (goingCallback != null) goingCallback.run(); return; } - + + mRecentTasks = mTaskPersister.restoreTasksLocked(); + if (!mRecentTasks.isEmpty()) { + mStackSupervisor.createStackForRestoredTaskHistory(mRecentTasks); + } + mTaskPersister.startPersisting(); + // Check to see if there are any update receivers to run. if (!mDidUpdate) { if (mWaitingUpdate) { @@ -17179,7 +17196,7 @@ public final class ActivityManagerService extends ActivityManagerNative /** * An implementation of IAppTask, that allows an app to manage its own tasks via - * {@link android.app.ActivityManager#AppTask}. We keep track of the callingUid to ensure that + * {@link android.app.ActivityManager.AppTask}. We keep track of the callingUid to ensure that * only the process that calls getAppTasks() can call the AppTask methods. */ class AppTaskImpl extends IAppTask.Stub { diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index dbe2ca1..b948c41 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -16,14 +16,15 @@ package com.android.server.am; +import android.app.ActivityManager.TaskDescription; import android.os.PersistableBundle; import android.os.Trace; import com.android.internal.app.ResolverActivity; +import com.android.internal.util.XmlUtils; import com.android.server.AttributeCache; import com.android.server.am.ActivityStack.ActivityState; import com.android.server.am.ActivityStackSupervisor.ActivityContainer; -import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ResultInfo; import android.content.ComponentName; @@ -48,7 +49,11 @@ import android.util.Slog; import android.util.TimeUtils; import android.view.IApplicationToken; import android.view.WindowManager; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; +import java.io.IOException; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -62,6 +67,19 @@ final class ActivityRecord { static final boolean DEBUG_SAVED_STATE = ActivityStackSupervisor.DEBUG_SAVED_STATE; final public static String RECENTS_PACKAGE_NAME = "com.android.systemui.recent"; + private static final String TAG_ACTIVITY = "activity"; + private static final String ATTR_ID = "id"; + private static final String TAG_INTENT = "intent"; + private static final String ATTR_USERID = "user_id"; + private static final String TAG_PERSISTABLEBUNDLE = "persistable_bundle"; + private static final String ATTR_LAUNCHEDFROMUID = "launched_from_uid"; + private static final String ATTR_LAUNCHEDFROMPACKAGE = "launched_from_package"; + private static final String ATTR_RESOLVEDTYPE = "resolved_type"; + private static final String ATTR_COMPONENTSPECIFIED = "component_specified"; + private static final String ATTR_TASKDESCRIPTIONLABEL = "task_description_label"; + private static final String ATTR_TASKDESCRIPTIONCOLOR = "task_description_color"; + private static final String ACTIVITY_ICON_SUFFIX = "_activity_icon_"; + final ActivityManagerService service; // owner final IApplicationToken.Stub appToken; // window manager token final ActivityInfo info; // all about me @@ -97,6 +115,7 @@ final class ActivityRecord { int windowFlags; // custom window flags for preview window. TaskRecord task; // the task this is in. ThumbnailHolder thumbHolder; // where our thumbnails should go. + long createTime = System.currentTimeMillis(); long displayStartTime; // when we started launching this activity long fullyDrawnStartTime; // when we started launching this activity long startTime; // last time this activity was started @@ -149,7 +168,7 @@ final class ActivityRecord { boolean mStartingWindowShown = false; ActivityContainer mInitialActivityContainer; - ActivityManager.TaskDescription taskDescription; // the recents information for this activity + TaskDescription taskDescription; // the recents information for this activity void dump(PrintWriter pw, String prefix) { final long now = SystemClock.uptimeMillis(); @@ -490,14 +509,6 @@ final class ActivityRecord { (newTask == null ? null : newTask.stack)); } } - if (inHistory && !finishing) { - if (task != null) { - task.numActivities--; - } - if (newTask != null) { - newTask.numActivities++; - } - } if (newThumbHolder == null) { newThumbHolder = newTask; } @@ -527,9 +538,6 @@ final class ActivityRecord { void putInHistory() { if (!inHistory) { inHistory = true; - if (task != null && !finishing) { - task.numActivities++; - } } } @@ -537,7 +545,6 @@ final class ActivityRecord { if (inHistory) { inHistory = false; if (task != null && !finishing) { - task.numActivities--; task = null; } clearOptionsLocked(); @@ -560,12 +567,13 @@ final class ActivityRecord { return mActivityType == APPLICATION_ACTIVITY_TYPE; } + boolean isPersistable() { + return (info.flags & ActivityInfo.FLAG_PERSISTABLE) != 0; + } + void makeFinishing() { if (!finishing) { finishing = true; - if (task != null && inHistory) { - task.numActivities--; - } if (stopped) { clearOptionsLocked(); } @@ -767,6 +775,9 @@ final class ActivityRecord { "Setting thumbnail of " + this + " holder " + thumbHolder + " to " + newThumbnail); thumbHolder.lastThumbnail = newThumbnail; + if (isPersistable()) { + mStackSupervisor.mService.notifyTaskPersisterLocked(task, false); + } } thumbHolder.lastDescription = description; } @@ -1042,7 +1053,132 @@ final class ActivityRecord { return null; } - private String activityTypeToString(int type) { + void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { + out.attribute(null, ATTR_ID, String.valueOf(createTime)); + out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid)); + if (launchedFromPackage != null) { + out.attribute(null, ATTR_LAUNCHEDFROMPACKAGE, launchedFromPackage); + } + if (resolvedType != null) { + out.attribute(null, ATTR_RESOLVEDTYPE, resolvedType); + } + out.attribute(null, ATTR_COMPONENTSPECIFIED, String.valueOf(componentSpecified)); + out.attribute(null, ATTR_USERID, String.valueOf(userId)); + if (taskDescription != null) { + final String label = taskDescription.getLabel(); + if (label != null) { + out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, label); + } + final int colorPrimary = taskDescription.getPrimaryColor(); + if (colorPrimary != 0) { + out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR, Integer.toHexString(colorPrimary)); + } + final Bitmap icon = taskDescription.getIcon(); + if (icon != null) { + TaskPersister.saveImage(icon, String.valueOf(task.taskId) + ACTIVITY_ICON_SUFFIX + + createTime); + } + } + + out.startTag(null, TAG_INTENT); + intent.saveToXml(out); + out.endTag(null, TAG_INTENT); + + if (isPersistable() && persistentState != null) { + out.startTag(null, TAG_PERSISTABLEBUNDLE); + persistentState.saveToXml(out); + out.endTag(null, TAG_PERSISTABLEBUNDLE); + } + } + + static ActivityRecord restoreFromXml(XmlPullParser in, int taskId, + ActivityStackSupervisor stackSupervisor) throws IOException, XmlPullParserException { + Intent intent = null; + PersistableBundle persistentState = null; + int launchedFromUid = 0; + String launchedFromPackage = null; + String resolvedType = null; + boolean componentSpecified = false; + int userId = 0; + String activityLabel = null; + int activityColor = 0; + long createTime = -1; + final int outerDepth = in.getDepth(); + + for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) { + final String attrName = in.getAttributeName(attrNdx); + final String attrValue = in.getAttributeValue(attrNdx); + if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "ActivityRecord: attribute name=" + + attrName + " value=" + attrValue); + if (ATTR_ID.equals(attrName)) { + createTime = Long.valueOf(attrValue); + } else if (ATTR_LAUNCHEDFROMUID.equals(attrName)) { + launchedFromUid = Integer.valueOf(attrValue); + } else if (ATTR_LAUNCHEDFROMPACKAGE.equals(attrName)) { + launchedFromPackage = attrValue; + } else if (ATTR_RESOLVEDTYPE.equals(attrName)) { + resolvedType = attrValue; + } else if (ATTR_COMPONENTSPECIFIED.equals(attrName)) { + componentSpecified = Boolean.valueOf(attrValue); + } else if (ATTR_USERID.equals(attrName)) { + userId = Integer.valueOf(attrValue); + } else if (ATTR_TASKDESCRIPTIONLABEL.equals(attrName)) { + activityLabel = attrValue; + } else if (ATTR_TASKDESCRIPTIONCOLOR.equals(attrName)) { + activityColor = (int) Long.parseLong(attrValue, 16); + } else { + Log.d(TAG, "Unknown ActivityRecord attribute=" + attrName); + } + } + + int event; + while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && + (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) { + if (event == XmlPullParser.START_TAG) { + final String name = in.getName(); + if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, + "ActivityRecord: START_TAG name=" + name); + if (TAG_INTENT.equals(name)) { + intent = Intent.restoreFromXml(in); + if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, + "ActivityRecord: intent=" + intent); + } else if (TAG_PERSISTABLEBUNDLE.equals(name)) { + persistentState = PersistableBundle.restoreFromXml(in); + if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, + "ActivityRecord: persistentState=" + persistentState); + } else { + Slog.w(TAG, "restoreActivity: unexpected name=" + name); + XmlUtils.skipCurrentTag(in); + } + } + } + + if (intent == null) { + Slog.e(TAG, "restoreActivity error intent=" + intent); + return null; + } + + final ActivityManagerService service = stackSupervisor.mService; + final ActivityInfo aInfo = stackSupervisor.resolveActivity(intent, resolvedType, 0, null, + null, userId); + final ActivityRecord r = new ActivityRecord(service, /*caller*/null, launchedFromUid, + launchedFromPackage, intent, resolvedType, aInfo, service.getConfiguration(), + null, null, 0, componentSpecified, stackSupervisor, null, null); + + r.persistentState = persistentState; + + Bitmap icon = null; + if (createTime >= 0) { + icon = TaskPersister.restoreImage(String.valueOf(taskId) + ACTIVITY_ICON_SUFFIX + + createTime); + } + r.taskDescription = new TaskDescription(activityLabel, icon, activityColor); + r.createTime = createTime; + + return r; + } + + private static String activityTypeToString(int type) { switch (type) { case APPLICATION_ACTIVITY_TYPE: return "APPLICATION_ACTIVITY_TYPE"; case HOME_ACTIVITY_TYPE: return "HOME_ACTIVITY_TYPE"; diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 33e59a7..d0ba118 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -30,6 +30,10 @@ import static com.android.server.am.ActivityManagerService.DEBUG_USER_LEAVING; import static com.android.server.am.ActivityManagerService.DEBUG_VISBILITY; import static com.android.server.am.ActivityManagerService.VALIDATE_TOKENS; +import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE; +import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE; +import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE; + import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE; import static com.android.server.am.ActivityStackSupervisor.DEBUG_APP; import static com.android.server.am.ActivityStackSupervisor.DEBUG_SAVED_STATE; @@ -863,7 +867,10 @@ final class ActivityStack { final ActivityRecord r = isInStackLocked(token); if (r != null) { mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r); - r.persistentState = persistentState; + if (persistentState != null) { + r.persistentState = persistentState; + mService.notifyTaskPersisterLocked(r.task, false); + } if (mPausingActivity == r) { if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r + (timeout ? " (due to timeout)" : " (pause complete)")); @@ -885,7 +892,10 @@ final class ActivityStack { mHandler.removeMessages(STOP_TIMEOUT_MSG, r); return; } - r.persistentState = persistentState; + if (persistentState != null) { + r.persistentState = persistentState; + mService.notifyTaskPersisterLocked(r.task, false); + } if (DEBUG_SAVED_STATE) Slog.i(TAG, "Saving icicle of " + r + ": " + icicle); if (icicle != null) { // If icicle is null, this is happening due to a timeout, so we @@ -1034,40 +1044,6 @@ final class ActivityStack { } } - /** - * Determine if home should be visible below the passed record. - * @param record activity we are querying for. - * @return true if home is visible below the passed activity, false otherwise. - */ - boolean isActivityOverHome(ActivityRecord record) { - // Start at record and go down, look for either home or a visible fullscreen activity. - final TaskRecord recordTask = record.task; - for (int taskNdx = mTaskHistory.indexOf(recordTask); taskNdx >= 0; --taskNdx) { - TaskRecord task = mTaskHistory.get(taskNdx); - final ArrayList<ActivityRecord> activities = task.mActivities; - final int startNdx = - task == recordTask ? activities.indexOf(record) : activities.size() - 1; - for (int activityNdx = startNdx; activityNdx >= 0; --activityNdx) { - final ActivityRecord r = activities.get(activityNdx); - if (r.isHomeActivity()) { - return true; - } - if (!r.finishing && r.fullscreen) { - // Passed activity is over a fullscreen activity. - return false; - } - } - if (task.mOnTopOfHome) { - // Got to the bottom of a task on top of home without finding a visible fullscreen - // activity. Home is visible. - return true; - } - } - // Got to the bottom of this stack and still don't know. If this is over the home stack - // then record is over home. May not work if we ever get more than two layers. - return mStackSupervisor.isFrontStack(this); - } - private void setVisibile(ActivityRecord r, boolean visible) { r.visible = visible; mWindowManager.setAppVisibility(r.appToken, visible); @@ -1097,7 +1073,8 @@ final class ActivityStack { for (int i = mStacks.indexOf(this) + 1; i < mStacks.size(); i++) { final ArrayList<TaskRecord> tasks = mStacks.get(i).getAllTasks(); for (int taskNdx = 0; taskNdx < tasks.size(); taskNdx++) { - final ArrayList<ActivityRecord> activities = tasks.get(taskNdx).mActivities; + final TaskRecord task = tasks.get(taskNdx); + final ArrayList<ActivityRecord> activities = task.mActivities; for (int activityNdx = 0; activityNdx < activities.size(); activityNdx++) { final ActivityRecord r = activities.get(activityNdx); @@ -1108,7 +1085,7 @@ final class ActivityStack { // - Full Screen Activity OR // - On top of Home and our stack is NOT home if (!r.finishing && r.visible && (r.fullscreen || - (!isHomeStack() && r.frontOfTask && tasks.get(taskNdx).mOnTopOfHome))) { + (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()))) { return false; } } @@ -1236,7 +1213,7 @@ final class ActivityStack { // At this point, nothing else needs to be shown if (DEBUG_VISBILITY) Slog.v(TAG, "Fullscreen: at " + r); behindFullscreen = true; - } else if (!isHomeStack() && r.frontOfTask && task.mOnTopOfHome) { + } else if (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()) { if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r); behindFullscreen = true; } @@ -1390,6 +1367,7 @@ final class ActivityStack { final boolean userLeaving = mStackSupervisor.mUserLeaving; mStackSupervisor.mUserLeaving = false; + final TaskRecord prevTask = prev != null ? prev.task : null; if (next == null) { // There are no more activities! Let's just start up the // Launcher... @@ -1397,7 +1375,10 @@ final class ActivityStack { if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: No more activities go home"); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); // Only resume home if on home display - return isOnHomeDisplay() && mStackSupervisor.resumeHomeActivity(prev); + final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ? + HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo(); + return isOnHomeDisplay() && + mStackSupervisor.resumeHomeStackTask(returnTaskType, prev); } next.delayedResume = false; @@ -1416,22 +1397,24 @@ final class ActivityStack { } final TaskRecord nextTask = next.task; - final TaskRecord prevTask = prev != null ? prev.task : null; if (prevTask != null && prevTask.stack == this && - prevTask.mOnTopOfHome && prev.finishing && prev.frontOfTask) { + prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) { if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); if (prevTask == nextTask) { prevTask.setFrontOfTask(); } else if (prevTask != topTask()) { - // This task is going away but it was supposed to return to the home task. + // This task is going away but it was supposed to return to the home stack. // Now the task above it has to return to the home task instead. final int taskNdx = mTaskHistory.indexOf(prevTask) + 1; - mTaskHistory.get(taskNdx).mOnTopOfHome = true; + mTaskHistory.get(taskNdx).setTaskToReturnTo(HOME_ACTIVITY_TYPE); } else { if (DEBUG_STATES && isOnHomeDisplay()) Slog.d(TAG, "resumeTopActivityLocked: Launching home next"); // Only resume home if on home display - return isOnHomeDisplay() && mStackSupervisor.resumeHomeActivity(prev); + final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ? + HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo(); + return isOnHomeDisplay() && + mStackSupervisor.resumeHomeStackTask(returnTaskType, prev); } } @@ -1802,10 +1785,11 @@ final class ActivityStack { ActivityStack lastStack = mStackSupervisor.getLastStack(); final boolean fromHome = lastStack.isHomeStack(); if (!isHomeStack() && (fromHome || topTask() != task)) { - task.mOnTopOfHome = fromHome; + task.setTaskToReturnTo(fromHome ? + lastStack.topTask().taskType : APPLICATION_ACTIVITY_TYPE); } } else { - task.mOnTopOfHome = false; + task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE); } mTaskHistory.remove(task); @@ -1821,6 +1805,7 @@ final class ActivityStack { ++stackNdx; } mTaskHistory.add(stackNdx, task); + updateTaskMovement(task, true); } final void startActivityLocked(ActivityRecord r, boolean newTask, @@ -2349,8 +2334,8 @@ final class ActivityStack { ActivityRecord next = topRunningActivityLocked(null); if (next != r) { final TaskRecord task = r.task; - if (r.frontOfTask && task == topTask() && task.mOnTopOfHome) { - mStackSupervisor.moveHomeToTop(); + if (r.frontOfTask && task == topTask() && task.isOverHomeStack()) { + mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo()); } } ActivityRecord top = mStackSupervisor.topRunningActivityLocked(); @@ -2834,8 +2819,9 @@ final class ActivityStack { if (task != null && task.removeActivity(r)) { if (DEBUG_STACK) Slog.i(TAG, "removeActivityFromHistoryLocked: last activity removed from " + this); - if (mStackSupervisor.isFrontStack(this) && task == topTask() && task.mOnTopOfHome) { - mStackSupervisor.moveHomeToTop(); + if (mStackSupervisor.isFrontStack(this) && task == topTask() && + task.isOverHomeStack()) { + mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo()); } removeTask(task); } @@ -3138,14 +3124,28 @@ final class ActivityStack { mWindowManager.prepareAppTransition(transit, false); } - void moveHomeTaskToTop() { + void updateTaskMovement(TaskRecord task, boolean toFront) { + if (task.isPersistable) { + task.mLastTimeMoved = System.currentTimeMillis(); + // Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most + // recently will be most negative, tasks sent to the bottom before that will be less + // negative. Similarly for recent tasks moved to the top which will be most positive. + if (!toFront) { + task.mLastTimeMoved *= -1; + } + } + } + + void moveHomeStackTaskToTop(int homeStackTaskType) { final int top = mTaskHistory.size() - 1; for (int taskNdx = top; taskNdx >= 0; --taskNdx) { final TaskRecord task = mTaskHistory.get(taskNdx); - if (task.isHomeTask()) { - if (DEBUG_TASKS || DEBUG_STACK) Slog.d(TAG, "moveHomeTaskToTop: moving " + task); + if (task.taskType == homeStackTaskType) { + if (DEBUG_TASKS || DEBUG_STACK) + Slog.d(TAG, "moveHomeStackTaskToTop: moving " + task); mTaskHistory.remove(taskNdx); mTaskHistory.add(top, task); + updateTaskMovement(task, true); mWindowManager.moveTaskToTop(task.taskId); return; } @@ -3247,19 +3247,19 @@ final class ActivityStack { mTaskHistory.remove(tr); mTaskHistory.add(0, tr); + updateTaskMovement(tr, false); // There is an assumption that moving a task to the back moves it behind the home activity. // We make sure here that some activity in the stack will launch home. - ActivityRecord lastActivity = null; int numTasks = mTaskHistory.size(); for (int taskNdx = numTasks - 1; taskNdx >= 1; --taskNdx) { final TaskRecord task = mTaskHistory.get(taskNdx); - if (task.mOnTopOfHome) { + if (task.isOverHomeStack()) { break; } if (taskNdx == 1) { // Set the last task before tr to go to home. - task.mOnTopOfHome = true; + task.setTaskToReturnTo(HOME_ACTIVITY_TYPE); } } @@ -3280,9 +3280,10 @@ final class ActivityStack { } final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null; - if (task == tr && tr.mOnTopOfHome || numTasks <= 1 && isOnHomeDisplay()) { - tr.mOnTopOfHome = false; - return mStackSupervisor.resumeHomeActivity(null); + if (task == tr && tr.isOverHomeStack() || numTasks <= 1 && isOnHomeDisplay()) { + final int taskToReturnTo = tr.getTaskToReturnTo(); + tr.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE); + return mStackSupervisor.resumeHomeStackTask(taskToReturnTo, null); } mStackSupervisor.resumeTopActivitiesLocked(); @@ -3723,10 +3724,14 @@ final class ActivityStack { final int taskNdx = mTaskHistory.indexOf(task); final int topTaskNdx = mTaskHistory.size() - 1; - if (task.mOnTopOfHome && taskNdx < topTaskNdx) { - mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true; + if (task.isOverHomeStack() && taskNdx < topTaskNdx) { + final TaskRecord nextTask = mTaskHistory.get(taskNdx + 1); + if (!nextTask.isOverHomeStack()) { + nextTask.setTaskToReturnTo(HOME_ACTIVITY_TYPE); + } } mTaskHistory.remove(task); + updateTaskMovement(task, true); if (task.mActivities.isEmpty()) { final boolean isVoiceSession = task.voiceSession != null; @@ -3758,7 +3763,8 @@ final class ActivityStack { TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, boolean toTop) { - TaskRecord task = new TaskRecord(taskId, info, intent, voiceSession, voiceInteractor); + TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession, + voiceInteractor); addTask(task, toTop, false); return task; } @@ -3773,6 +3779,7 @@ final class ActivityStack { insertTaskAtTop(task); } else { mTaskHistory.add(0, task); + updateTaskMovement(task, false); } if (!moving && task.voiceSession != null) { try { diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 252c0bb..c1a4643 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -31,6 +31,9 @@ import static com.android.server.am.ActivityManagerService.DEBUG_TASKS; import static com.android.server.am.ActivityManagerService.DEBUG_USER_LEAVING; import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG; import static com.android.server.am.ActivityManagerService.TAG; +import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE; +import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE; +import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE; import android.app.Activity; import android.app.ActivityManager; @@ -318,18 +321,27 @@ public final class ActivityStackSupervisor implements DisplayListener { } } - void moveHomeToTop() { + void moveHomeStackTaskToTop(int homeStackTaskType) { + if (homeStackTaskType == RECENTS_ACTIVITY_TYPE) { + mWindowManager.showRecentApps(); + return; + } moveHomeStack(true); - mHomeStack.moveHomeTaskToTop(); + mHomeStack.moveHomeStackTaskToTop(homeStackTaskType); } - boolean resumeHomeActivity(ActivityRecord prev) { - moveHomeToTop(); + boolean resumeHomeStackTask(int homeStackTaskType, ActivityRecord prev) { + if (homeStackTaskType == RECENTS_ACTIVITY_TYPE) { + mWindowManager.showRecentApps(); + return false; + } + moveHomeStackTaskToTop(homeStackTaskType); if (prev != null) { - prev.task.mOnTopOfHome = false; + prev.task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE); } + ActivityRecord r = mHomeStack.topRunningActivityLocked(null); - if (r != null && r.isHomeActivity()) { + if (r != null && (r.isHomeActivity() || r.isRecentsActivity())) { mService.setFocusedActivityLocked(r); return resumeTopActivitiesLocked(mHomeStack, prev, null); } @@ -370,6 +382,12 @@ public final class ActivityStackSupervisor implements DisplayListener { return null; } + void setNextTaskId(int taskId) { + if (taskId > mCurTaskId) { + mCurTaskId = taskId; + } + } + int getNextTaskId() { do { mCurTaskId++; @@ -677,7 +695,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } void startHomeActivity(Intent intent, ActivityInfo aInfo) { - moveHomeToTop(); + moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE); startActivityLocked(null, intent, null, aInfo, null, null, null, null, 0, 0, 0, null, 0, null, false, null, null); } @@ -1609,7 +1627,7 @@ public final class ActivityStackSupervisor implements DisplayListener { (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) { // Caller wants to appear on home activity. - intentActivity.task.mOnTopOfHome = true; + intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE); } options = null; } @@ -1793,6 +1811,11 @@ public final class ActivityStackSupervisor implements DisplayListener { newTaskInfo != null ? newTaskInfo : r.info, newTaskIntent != null ? newTaskIntent : intent, voiceSession, voiceInteractor, true), null, true); + if (sourceRecord == null) { + // Launched from a service or notification or task that is finishing. + r.task.setTaskToReturnTo(isFrontStack(mHomeStack) ? + mHomeStack.topTask().taskType : RECENTS_ACTIVITY_TYPE); + } if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " + r.task); } else { @@ -1805,7 +1828,7 @@ public final class ActivityStackSupervisor implements DisplayListener { == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) { // Caller wants to appear on home activity, so before starting // their own activity we will bring home to the front. - r.task.mOnTopOfHome = r.task.stack.isOnHomeDisplay(); + r.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE); } } } else if (sourceRecord != null) { @@ -2156,7 +2179,7 @@ public final class ActivityStackSupervisor implements DisplayListener { if ((flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0) { // Caller wants the home activity moved with it. To accomplish this, // we'll just indicate that this task returns to the home task. - task.mOnTopOfHome = true; + task.setTaskToReturnTo(HOME_ACTIVITY_TYPE); } task.stack.moveTaskToFrontLocked(task, null, options); if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack=" @@ -2250,6 +2273,26 @@ public final class ActivityStackSupervisor implements DisplayListener { return mLastStackId; } + void createStackForRestoredTaskHistory(ArrayList<TaskRecord> tasks) { + int stackId = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY); + final ActivityStack stack = getStack(stackId); + for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { + final TaskRecord task = tasks.get(taskNdx); + stack.addTask(task, false, false); + final int taskId = task.taskId; + final ArrayList<ActivityRecord> activities = task.mActivities; + for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { + final ActivityRecord r = activities.get(activityNdx); + mWindowManager.addAppToken(0, r.appToken, taskId, stackId, + r.info.screenOrientation, r.fullscreen, + (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, + r.userId, r.info.configChanges); + } + mWindowManager.addTask(taskId, stackId, false); + } + resumeHomeStackTask(HOME_ACTIVITY_TYPE, null); + } + void moveTaskToStack(int taskId, int stackId, boolean toTop) { final TaskRecord task = anyTaskForIdLocked(taskId); if (task == null) { @@ -2504,7 +2547,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } } else { // Stack was moved to another display while user was swapped out. - resumeHomeActivity(null); + resumeHomeStackTask(HOME_ACTIVITY_TYPE, null); } return homeInFront; } diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java new file mode 100644 index 0000000..ba3f2fe --- /dev/null +++ b/services/core/java/com/android/server/am/TaskPersister.java @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.am; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Debug; +import android.os.SystemClock; +import android.util.ArraySet; +import android.util.AtomicFile; +import android.util.Slog; +import android.util.Xml; +import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.XmlUtils; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; + +public class TaskPersister { + static final String TAG = "TaskPersister"; + static final boolean DEBUG = false; + + /** When in slow mode don't write tasks out faster than this */ + private static final long INTER_TASK_DELAY_MS = 60000; + private static final long DEBUG_INTER_TASK_DELAY_MS = 5000; + + private static final String RECENTS_FILENAME = "_task"; + private static final String TASKS_DIRNAME = "recent_tasks"; + private static final String TASK_EXTENSION = ".xml"; + private static final String IMAGES_DIRNAME = "recent_images"; + private static final String IMAGE_EXTENSION = ".png"; + + private static final String TAG_TASK = "task"; + + private static File sImagesDir; + private static File sTasksDir; + + private final ActivityManagerService mService; + private final ActivityStackSupervisor mStackSupervisor; + + private boolean mRecentsChanged = false; + + private final LazyTaskWriterThread mLazyTaskWriterThread; + + TaskPersister(File systemDir, ActivityStackSupervisor stackSupervisor) { + sTasksDir = new File(systemDir, TASKS_DIRNAME); + if (!sTasksDir.exists()) { + if (!sTasksDir.mkdir()) { + Slog.e(TAG, "Failure creating tasks directory " + sTasksDir); + } + } + + sImagesDir = new File(systemDir, IMAGES_DIRNAME); + if (!sImagesDir.exists()) { + if (!sImagesDir.mkdir()) { + Slog.e(TAG, "Failure creating images directory " + sImagesDir); + } + } + + mStackSupervisor = stackSupervisor; + mService = stackSupervisor.mService; + + mLazyTaskWriterThread = new LazyTaskWriterThread("LazyTaskWriterThread"); + } + + void startPersisting() { + mLazyTaskWriterThread.start(); + } + + public void notify(TaskRecord task, boolean flush) { + if (DEBUG) Slog.d(TAG, "notify: task=" + task + " flush=" + flush + + " Callers=" + Debug.getCallers(4)); + if (task != null) { + task.needsPersisting = true; + } + synchronized (this) { + mLazyTaskWriterThread.mSlow = !flush; + mRecentsChanged = true; + notifyAll(); + } + } + + private StringWriter saveToXml(TaskRecord task) throws IOException, XmlPullParserException { + if (DEBUG) Slog.d(TAG, "saveToXml: task=" + task); + final XmlSerializer xmlSerializer = new FastXmlSerializer(); + StringWriter stringWriter = new StringWriter(); + xmlSerializer.setOutput(stringWriter); + + if (DEBUG) xmlSerializer.setFeature( + "http://xmlpull.org/v1/doc/features.html#indent-output", true); + + // save task + xmlSerializer.startDocument(null, true); + + xmlSerializer.startTag(null, TAG_TASK); + task.saveToXml(xmlSerializer); + xmlSerializer.endTag(null, TAG_TASK); + + xmlSerializer.endDocument(); + xmlSerializer.flush(); + + return stringWriter; + } + + static void saveImage(Bitmap image, String filename) throws IOException { + if (DEBUG) Slog.d(TAG, "saveImage: filename=" + filename); + FileOutputStream imageFile = null; + try { + imageFile = new FileOutputStream(new File(sImagesDir, filename + IMAGE_EXTENSION)); + image.compress(Bitmap.CompressFormat.PNG, 100, imageFile); + } catch (Exception e) { + Slog.e(TAG, "saveImage: unable to save " + filename, e); + } finally { + if (imageFile != null) { + imageFile.close(); + } + } + } + + ArrayList<TaskRecord> restoreTasksLocked() { + final ArrayList<TaskRecord> tasks = new ArrayList<TaskRecord>(); + ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>(); + + File[] recentFiles = sTasksDir.listFiles(); + if (recentFiles == null) { + Slog.e(TAG, "Unable to list files from " + sTasksDir); + return tasks; + } + + for (int taskNdx = 0; taskNdx < recentFiles.length; ++taskNdx) { + File taskFile = recentFiles[taskNdx]; + if (DEBUG) Slog.d(TAG, "restoreTasksLocked: taskFile=" + taskFile.getName()); + BufferedReader reader = null; + try { + reader = new BufferedReader(new FileReader(taskFile)); + final XmlPullParser in = Xml.newPullParser(); + in.setInput(reader); + + int event; + while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && + event != XmlPullParser.END_TAG) { + final String name = in.getName(); + if (event == XmlPullParser.START_TAG) { + if (DEBUG) Slog.d(TAG, "restoreTasksLocked: START_TAG name=" + name); + if (TAG_TASK.equals(name)) { + final TaskRecord task = + TaskRecord.restoreFromXml(in, mStackSupervisor); + if (DEBUG) Slog.d(TAG, "restoreTasksLocked: restored task=" + task); + if (task != null) { + tasks.add(task); + final int taskId = task.taskId; + recoveredTaskIds.add(taskId); + mStackSupervisor.setNextTaskId(taskId); + } + } else { + Slog.e(TAG, "restoreTasksLocked Unknown xml event=" + event + " name=" + + name); + } + } + XmlUtils.skipCurrentTag(in); + } + } catch (IOException e) { + Slog.e(TAG, "Unable to parse " + taskFile + ". Error " + e); + } catch (XmlPullParserException e) { + Slog.e(TAG, "Unable to parse " + taskFile + ". Error " + e); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + } + } + } + } + + if (!DEBUG) { + removeObsoleteFiles(recoveredTaskIds); + } + + TaskRecord[] tasksArray = new TaskRecord[tasks.size()]; + tasks.toArray(tasksArray); + Arrays.sort(tasksArray, new Comparator<TaskRecord>() { + @Override + public int compare(TaskRecord lhs, TaskRecord rhs) { + final long diff = lhs.mLastTimeMoved - rhs.mLastTimeMoved; + if (diff < 0) { + return -1; + } else if (diff > 0) { + return +1; + } else { + return 0; + } + } + }); + + return new ArrayList<TaskRecord>(Arrays.asList(tasksArray)); + } + + private void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, File[] files) { + for (int fileNdx = 0; fileNdx < files.length; ++fileNdx) { + File file = files[fileNdx]; + String filename = file.getName(); + final int taskIdEnd = filename.indexOf('_') + 1; + if (taskIdEnd > 0) { + final int taskId; + try { + taskId = Integer.valueOf(filename.substring(0, taskIdEnd)); + } catch (Exception e) { + if (DEBUG) Slog.d(TAG, "removeObsoleteFile: Can't parse file=" + + file.getName()); + file.delete(); + continue; + } + if (!persistentTaskIds.contains(taskId)) { + if (DEBUG) Slog.d(TAG, "removeObsoleteFile: deleting file=" + file.getName()); + file.delete(); + } + } + } + } + + private void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds) { + removeObsoleteFiles(persistentTaskIds, sTasksDir.listFiles()); + removeObsoleteFiles(persistentTaskIds, sImagesDir.listFiles()); + } + + static Bitmap restoreImage(String filename) { + if (DEBUG) Slog.d(TAG, "restoreImage: restoring " + filename); + return BitmapFactory.decodeFile(sImagesDir + File.separator + filename + IMAGE_EXTENSION); + } + + private class LazyTaskWriterThread extends Thread { + boolean mSlow = true; + + LazyTaskWriterThread(String name) { + super(name); + } + + @Override + public void run() { + ArraySet<Integer> persistentTaskIds = new ArraySet<Integer>(); + while (true) { + // If mSlow, then delay between each call to saveToXml(). + synchronized (TaskPersister.this) { + long now = SystemClock.uptimeMillis(); + final long releaseTime = + now + (DEBUG ? DEBUG_INTER_TASK_DELAY_MS: INTER_TASK_DELAY_MS); + while (mSlow && now < releaseTime) { + try { + if (DEBUG) Slog.d(TAG, "LazyTaskWriter: waiting " + + (releaseTime - now)); + TaskPersister.this.wait(releaseTime - now); + } catch (InterruptedException e) { + } + now = SystemClock.uptimeMillis(); + } + } + + StringWriter stringWriter = null; + TaskRecord task = null; + synchronized(mService) { + final ArrayList<TaskRecord> tasks = mService.mRecentTasks; + persistentTaskIds.clear(); + int taskNdx; + for (taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { + task = tasks.get(taskNdx); + if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task + " persistable=" + + task.isPersistable + " needsPersisting=" + task.needsPersisting); + if (task.isPersistable) { + persistentTaskIds.add(task.taskId); + + if (task.needsPersisting) { + try { + stringWriter = saveToXml(task); + break; + } catch (IOException e) { + } catch (XmlPullParserException e) { + } finally { + task.needsPersisting = false; + } + } + } + } + } + + if (stringWriter != null) { + // Write out xml file while not holding mService lock. + FileOutputStream file = null; + AtomicFile atomicFile = null; + try { + atomicFile = new AtomicFile(new File(sTasksDir, + String.valueOf(task.taskId) + RECENTS_FILENAME + TASK_EXTENSION)); + file = atomicFile.startWrite(); + file.write(stringWriter.toString().getBytes()); + file.write('\n'); + atomicFile.finishWrite(file); + } catch (IOException e) { + if (file != null) { + atomicFile.failWrite(file); + } + Slog.e(TAG, "Unable to open " + atomicFile + " for persisting. " + e); + } + } else { + // Made it through the entire list and didn't find anything new that needed + // persisting. + if (!DEBUG) { + removeObsoleteFiles(persistentTaskIds); + } + + // Wait here for someone to call setRecentsChanged(). + synchronized (TaskPersister.this) { + while (!mRecentsChanged) { + if (DEBUG) Slog.d(TAG, "LazyTaskWriter: Waiting."); + try { + TaskPersister.this.wait(); + } catch (InterruptedException e) { + } + } + mRecentsChanged = false; + if (DEBUG) Slog.d(TAG, "LazyTaskWriter: Awake"); + } + } + // Some recents file needs to be written. + } + } + } +} diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 6d66b29..c07bc1e 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -17,6 +17,9 @@ package com.android.server.am; import static com.android.server.am.ActivityManagerService.TAG; +import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE; +import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE; +import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE; import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE; import android.app.Activity; @@ -27,15 +30,38 @@ import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; import android.graphics.Bitmap; +import android.os.SystemClock; import android.os.UserHandle; import android.service.voice.IVoiceInteractionSession; import android.util.Slog; import com.android.internal.app.IVoiceInteractor; +import com.android.internal.util.XmlUtils; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; +import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; final class TaskRecord extends ThumbnailHolder { + private static final String TAG_TASK = "task"; + private static final String ATTR_TASKID = "task_id"; + private static final String TAG_INTENT = "intent"; + private static final String TAG_AFFINITYINTENT = "affinity_intent"; + private static final String ATTR_REALACTIVITY = "real_activity"; + private static final String ATTR_ORIGACTIVITY = "orig_activity"; + private static final String TAG_ACTIVITY = "activity"; + private static final String ATTR_AFFINITY = "affinity"; + private static final String ATTR_ROOTHASRESET = "root_has_reset"; + private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode"; + private static final String ATTR_USERID = "user_id"; + private static final String ATTR_TASKTYPE = "task_type"; + private static final String ATTR_LASTDESCRIPTION = "last_description"; + private static final String ATTR_LASTTIMEMOVED = "last_time_moved"; + + private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail"; + final int taskId; // Unique identifier for this task. final String affinity; // The affinity name for this task, or null. final IVoiceInteractionSession voiceSession; // Voice interaction session driving task @@ -62,25 +88,64 @@ final class TaskRecord extends ThumbnailHolder { new ActivityManager.TaskDescription(); /** List of all activities in the task arranged in history order */ - final ArrayList<ActivityRecord> mActivities = new ArrayList<ActivityRecord>(); + final ArrayList<ActivityRecord> mActivities; /** Current stack */ ActivityStack stack; /** Takes on same set of values as ActivityRecord.mActivityType */ - private int mTaskType; + int taskType; + + /** Takes on same value as first root activity */ + boolean isPersistable = false; + + /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for + * determining the order when restoring. Sign indicates whether last task movement was to front + * (positive) or back (negative). Absolute value indicates time. */ + long mLastTimeMoved = System.currentTimeMillis(); + + /** True if persistable, has changed, and has not yet been persisted */ + boolean needsPersisting = false; - /** Launch the home activity when leaving this task. Will be false for tasks that are not on - * Display.DEFAULT_DISPLAY. */ - boolean mOnTopOfHome = false; + /** Indication of what to run next when task exits. Use ActivityRecord types. + * ActivityRecord.APPLICATION_ACTIVITY_TYPE indicates to resume the task below this one in the + * task stack. */ + private int mTaskToReturnTo = APPLICATION_ACTIVITY_TYPE; - TaskRecord(int _taskId, ActivityInfo info, Intent _intent, + final ActivityManagerService mService; + + TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent, IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) { + mService = service; taskId = _taskId; affinity = info.taskAffinity; voiceSession = _voiceSession; voiceInteractor = _voiceInteractor; setIntent(_intent, info); + mActivities = new ArrayList<ActivityRecord>(); + } + + TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, Intent _affinityIntent, + String _affinity, ComponentName _realActivity, ComponentName _origActivity, + boolean _rootWasReset, boolean _askedCompatMode, int _taskType, int _userId, + String _lastDescription, ArrayList<ActivityRecord> activities, long lastTimeMoved) { + mService = service; + taskId = _taskId; + intent = _intent; + affinityIntent = _affinityIntent; + affinity = _affinity; + voiceSession = null; + voiceInteractor = null; + realActivity = _realActivity; + origActivity = _origActivity; + rootWasReset = _rootWasReset; + askedCompatMode = _askedCompatMode; + taskType = _taskType; + mTaskToReturnTo = HOME_ACTIVITY_TYPE; + userId = _userId; + lastDescription = _lastDescription; + mActivities = activities; + mLastTimeMoved = lastTimeMoved; } void touchActiveTime() { @@ -144,6 +209,14 @@ final class TaskRecord extends ThumbnailHolder { } } + void setTaskToReturnTo(int taskToReturnTo) { + mTaskToReturnTo = taskToReturnTo; + } + + int getTaskToReturnTo() { + return mTaskToReturnTo; + } + void disposeThumbnail() { super.disposeThumbnail(); for (int i=mActivities.size()-1; i>=0; i--) { @@ -237,12 +310,16 @@ final class TaskRecord extends ThumbnailHolder { } // Only set this based on the first activity if (mActivities.isEmpty()) { - mTaskType = r.mActivityType; + taskType = r.mActivityType; + isPersistable = r.isPersistable(); } else { // Otherwise make all added activities match this one. - r.mActivityType = mTaskType; + r.mActivityType = taskType; } mActivities.add(index, r); + if (r.isPersistable()) { + mService.notifyTaskPersisterLocked(this, false); + } } /** @return true if this was the last activity in the task */ @@ -251,6 +328,9 @@ final class TaskRecord extends ThumbnailHolder { // Was previously in list. numFullscreen--; } + if (r.isPersistable()) { + mService.notifyTaskPersisterLocked(this, false); + } return mActivities.size() == 0; } @@ -270,7 +350,14 @@ final class TaskRecord extends ThumbnailHolder { if (r.finishing) { continue; } - if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear", false)) { + if (stack == null) { + // Task was restored from persistent storage. + r.takeFromHistory(); + mActivities.remove(activityNdx); + --activityNdx; + --numActivities; + } else if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear", + false)) { --activityNdx; --numActivities; } @@ -354,11 +441,13 @@ final class TaskRecord extends ThumbnailHolder { } public Bitmap getTaskTopThumbnailLocked() { - final ActivityRecord resumedActivity = stack.mResumedActivity; - if (resumedActivity != null && resumedActivity.task == this) { - // This task is the current resumed task, we just need to take - // a screenshot of it and return that. - return stack.screenshotActivities(resumedActivity); + if (stack != null) { + final ActivityRecord resumedActivity = stack.mResumedActivity; + if (resumedActivity != null && resumedActivity.task == this) { + // This task is the current resumed task, we just need to take + // a screenshot of it and return that. + return stack.screenshotActivities(resumedActivity); + } } // Return the information about the task, to figure out the top // thumbnail to return. @@ -399,11 +488,15 @@ final class TaskRecord extends ThumbnailHolder { } boolean isHomeTask() { - return mTaskType == ActivityRecord.HOME_ACTIVITY_TYPE; + return taskType == HOME_ACTIVITY_TYPE; } boolean isApplicationTask() { - return mTaskType == ActivityRecord.APPLICATION_ACTIVITY_TYPE; + return taskType == APPLICATION_ACTIVITY_TYPE; + } + + boolean isOverHomeStack() { + return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE; } public TaskAccessInfo getTaskAccessInfoLocked() { @@ -493,7 +586,7 @@ final class TaskRecord extends ThumbnailHolder { int activityNdx; final int numActivities = mActivities.size(); for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities; - ++activityNdx) { + ++activityNdx) { final ActivityRecord r = mActivities.get(activityNdx); if (r.intent != null && (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) @@ -528,14 +621,152 @@ final class TaskRecord extends ThumbnailHolder { } } + void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { + Slog.i(TAG, "Saving task=" + this); + + out.attribute(null, ATTR_TASKID, String.valueOf(taskId)); + if (realActivity != null) { + out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString()); + } + if (origActivity != null) { + out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString()); + } + if (affinity != null) { + out.attribute(null, ATTR_AFFINITY, affinity); + } + out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset)); + out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode)); + out.attribute(null, ATTR_USERID, String.valueOf(userId)); + out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType)); + out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved)); + if (lastDescription != null) { + out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString()); + } + + if (affinityIntent != null) { + out.startTag(null, TAG_AFFINITYINTENT); + affinityIntent.saveToXml(out); + out.endTag(null, TAG_AFFINITYINTENT); + } + + out.startTag(null, TAG_INTENT); + intent.saveToXml(out); + out.endTag(null, TAG_INTENT); + + final ArrayList<ActivityRecord> activities = mActivities; + final int numActivities = activities.size(); + for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { + final ActivityRecord r = activities.get(activityNdx); + if (!r.isPersistable() || (r.intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) == + Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) { + break; + } + out.startTag(null, TAG_ACTIVITY); + r.saveToXml(out); + out.endTag(null, TAG_ACTIVITY); + } + + final Bitmap thumbnail = getTaskTopThumbnailLocked(); + if (thumbnail != null) { + TaskPersister.saveImage(thumbnail, String.valueOf(taskId) + TASK_THUMBNAIL_SUFFIX); + } + } + + static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) + throws IOException, XmlPullParserException { + Intent intent = null; + Intent affinityIntent = null; + ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>(); + ComponentName realActivity = null; + ComponentName origActivity = null; + String affinity = null; + boolean rootHasReset = false; + boolean askedCompatMode = false; + int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE; + int userId = 0; + String lastDescription = null; + long lastTimeOnTop = 0; + int taskId = -1; + final int outerDepth = in.getDepth(); + + for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) { + final String attrName = in.getAttributeName(attrNdx); + final String attrValue = in.getAttributeValue(attrNdx); + if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" + + attrName + " value=" + attrValue); + if (ATTR_TASKID.equals(attrName)) { + taskId = Integer.valueOf(attrValue); + } else if (ATTR_REALACTIVITY.equals(attrName)) { + realActivity = ComponentName.unflattenFromString(attrValue); + } else if (ATTR_ORIGACTIVITY.equals(attrName)) { + origActivity = ComponentName.unflattenFromString(attrValue); + } else if (ATTR_AFFINITY.equals(attrName)) { + affinity = attrValue; + } else if (ATTR_ROOTHASRESET.equals(attrName)) { + rootHasReset = Boolean.valueOf(attrValue); + } else if (ATTR_ASKEDCOMPATMODE.equals(attrName)) { + askedCompatMode = Boolean.valueOf(attrValue); + } else if (ATTR_USERID.equals(attrName)) { + userId = Integer.valueOf(attrValue); + } else if (ATTR_TASKTYPE.equals(attrName)) { + taskType = Integer.valueOf(attrValue); + } else if (ATTR_LASTDESCRIPTION.equals(attrName)) { + lastDescription = attrValue; + } else if (ATTR_LASTTIMEMOVED.equals(attrName)) { + lastTimeOnTop = Long.valueOf(attrValue); + } else { + Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName); + } + } + + int event; + while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && + (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) { + if (event == XmlPullParser.START_TAG) { + final String name = in.getName(); + if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" + + name); + if (TAG_AFFINITYINTENT.equals(name)) { + affinityIntent = Intent.restoreFromXml(in); + } else if (TAG_INTENT.equals(name)) { + intent = Intent.restoreFromXml(in); + } else if (TAG_ACTIVITY.equals(name)) { + ActivityRecord activity = + ActivityRecord.restoreFromXml(in, taskId, stackSupervisor); + if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" + + activity); + if (activity != null) { + activities.add(activity); + } + } else { + Slog.e(TAG, "restoreTask: Unexpected name=" + name); + XmlUtils.skipCurrentTag(in); + } + } + } + + final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent, + affinityIntent, affinity, realActivity, origActivity, rootHasReset, + askedCompatMode, taskType, userId, lastDescription, activities, lastTimeOnTop); + + for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) { + final ActivityRecord r = activities.get(activityNdx); + r.thumbHolder = r.task = task; + } + + task.lastThumbnail = TaskPersister.restoreImage(taskId + TASK_THUMBNAIL_SUFFIX); + + Slog.i(TAG, "Restored task=" + task); + return task; + } + void dump(PrintWriter pw, String prefix) { - if (numActivities != 0 || rootWasReset || userId != 0 || numFullscreen != 0) { - pw.print(prefix); pw.print("numActivities="); pw.print(numActivities); - pw.print(" rootWasReset="); pw.print(rootWasReset); + if (rootWasReset || userId != 0 || numFullscreen != 0) { + pw.print(prefix); pw.print(" rootWasReset="); pw.print(rootWasReset); pw.print(" userId="); pw.print(userId); - pw.print(" mTaskType="); pw.print(mTaskType); + pw.print(" taskType="); pw.print(taskType); pw.print(" numFullscreen="); pw.print(numFullscreen); - pw.print(" mOnTopOfHome="); pw.println(mOnTopOfHome); + pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo); } if (affinity != null) { pw.print(prefix); pw.print("affinity="); pw.println(affinity); diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index 584145f..b94ea62 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -175,7 +175,10 @@ abstract public class ManagedServices { public void registerService(IInterface service, ComponentName component, int userid) { checkNotNull(service); - registerServiceImpl(service, component, userid); + ManagedServiceInfo info = registerServiceImpl(service, component, userid); + if (info != null) { + onServiceAdded(info); + } } /** @@ -464,7 +467,7 @@ abstract public class ManagedServices { } } - private void registerServiceImpl(final IInterface service, + private ManagedServiceInfo registerServiceImpl(final IInterface service, final ComponentName component, final int userid) { synchronized (mMutex) { try { @@ -472,10 +475,12 @@ abstract public class ManagedServices { true /*isSystem*/, null, Build.VERSION_CODES.L); service.asBinder().linkToDeath(info, 0); mServices.add(info); + return info; } catch (RemoteException e) { // already dead } } + return null; } /** diff --git a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java index 125158f..db17f3a 100644 --- a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java +++ b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java @@ -20,7 +20,6 @@ import android.app.Notification; import android.content.Context; import android.util.Slog; -import com.android.internal.R; import com.android.server.notification.NotificationManagerService.NotificationRecord; /** @@ -39,7 +38,7 @@ public class NotificationIntrusivenessExtractor implements NotificationSignalExt if (DBG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + "."); } - public RankingFuture process(NotificationRecord record) { + public RankingReconsideration process(NotificationRecord record) { if (record == null || record.getNotification() == null) { if (DBG) Slog.d(TAG, "skipping empty notification"); return null; @@ -54,10 +53,15 @@ public class NotificationIntrusivenessExtractor implements NotificationSignalExt record.setRecentlyIntusive(true); } - return new RankingFuture(record, HANG_TIME_MS) { + return new RankingReconsideration(record.getKey(), HANG_TIME_MS) { @Override public void work() { - mRecord.setRecentlyIntusive(false); + // pass + } + + @Override + public void applyChangesLocked(NotificationRecord record) { + record.setRecentlyIntusive(false); } }; } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 0b3e02a..bbc3091 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -111,7 +111,6 @@ import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.NoSuchElementException; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; /** {@hide} */ @@ -453,11 +452,10 @@ public class NotificationManagerService extends SystemService { - public static final class NotificationRecord - { + public static final class NotificationRecord { final StatusBarNotification sbn; SingleNotificationStats stats; - IBinder statusBarKey; + boolean isCanceled; // These members are used by NotificationSignalExtractors // to communicate with the ranking module. @@ -472,6 +470,7 @@ public class NotificationManagerService extends SystemService { public Notification getNotification() { return sbn.getNotification(); } public int getFlags() { return sbn.getNotification().flags; } public int getUserId() { return sbn.getUserId(); } + public String getKey() { return sbn.getKey(); } void dump(PrintWriter pw, String prefix, Context baseContext) { final Notification notification = sbn.getNotification(); @@ -555,13 +554,13 @@ public class NotificationManagerService extends SystemService { return mContactAffinity; } - public boolean isRecentlyIntrusive() { - return mRecentlyIntrusive; - } - public void setRecentlyIntusive(boolean recentlyIntrusive) { mRecentlyIntrusive = recentlyIntrusive; } + + public boolean isRecentlyIntrusive() { + return mRecentlyIntrusive; + } } private static final class ToastRecord @@ -1263,7 +1262,7 @@ public class NotificationManagerService extends SystemService { @Override public void registerListener(final INotificationListener listener, final ComponentName component, final int userid) { - checkCallerIsSystem(); + enforceSystemOrSystemUI("INotificationManager.registerListener"); mListeners.registerService(listener, component, userid); } @@ -1634,8 +1633,8 @@ public class NotificationManagerService extends SystemService { if (!mSignalExtractors.isEmpty()) { for (NotificationSignalExtractor extractor : mSignalExtractors) { try { - RankingFuture future = extractor.process(r); - scheduleRankingReconsideration(future); + RankingReconsideration recon = extractor.process(r); + scheduleRankingReconsideration(recon); } catch (Throwable t) { Slog.w(TAG, "NotificationSignalExtractor failed.", t); } @@ -1668,7 +1667,7 @@ public class NotificationManagerService extends SystemService { "pkg=" + pkg + " canInterrupt=" + canInterrupt + " intercept=" + intercept); synchronized (mNotificationList) { NotificationRecord old = null; - int index = indexOfNotificationLocked(pkg, tag, id, userId); + int index = indexOfNotificationLocked(n.getKey()); if (index < 0) { mNotificationList.add(r); mUsageStats.registerPostedByApp(r); @@ -1677,12 +1676,8 @@ public class NotificationManagerService extends SystemService { mNotificationList.set(index, r); mUsageStats.registerUpdatedByApp(r, old); // Make sure we don't lose the foreground service state. - if (old != null) { - notification.flags |= - old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE; - } - } - if (old != null) { + notification.flags |= + old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE; mNotificationsByKey.remove(old.sbn.getKey()); } mNotificationsByKey.put(n.getKey(), r); @@ -1705,18 +1700,17 @@ public class NotificationManagerService extends SystemService { } if (notification.icon != 0) { - if (old != null && old.statusBarKey != null) { - r.statusBarKey = old.statusBarKey; + if (old != null && !old.isCanceled) { final long identity = Binder.clearCallingIdentity(); try { - mStatusBar.updateNotification(r.statusBarKey, n); + mStatusBar.updateNotification(n); } finally { Binder.restoreCallingIdentity(identity); } } else { final long identity = Binder.clearCallingIdentity(); try { - r.statusBarKey = mStatusBar.addNotification(n); + mStatusBar.addNotification(n); if ((n.getNotification().flags & Notification.FLAG_SHOW_LIGHTS) != 0 && canInterrupt) { mAttentionLight.pulse(); @@ -1733,10 +1727,10 @@ public class NotificationManagerService extends SystemService { mListeners.notifyPostedLocked(r.sbn, cloneNotificationListLocked()); } else { Slog.e(TAG, "Not posting notification with icon==0: " + notification); - if (old != null && old.statusBarKey != null) { + if (old != null && !old.isCanceled) { final long identity = Binder.clearCallingIdentity(); try { - mStatusBar.removeNotification(old.statusBarKey); + mStatusBar.removeNotification(r.getKey()); } finally { Binder.restoreCallingIdentity(identity); } @@ -1986,39 +1980,40 @@ public class NotificationManagerService extends SystemService { } } - private void scheduleRankingReconsideration(RankingFuture future) { - if (future != null) { - Message m = Message.obtain(mRankingHandler, MESSAGE_RECONSIDER_RANKING, future); - long delay = future.getDelay(TimeUnit.MILLISECONDS); + private void scheduleRankingReconsideration(RankingReconsideration recon) { + if (recon != null) { + Message m = Message.obtain(mRankingHandler, MESSAGE_RECONSIDER_RANKING, recon); + long delay = recon.getDelay(TimeUnit.MILLISECONDS); mRankingHandler.sendMessageDelayed(m, delay); } } private void handleRankingReconsideration(Message message) { - if (!(message.obj instanceof RankingFuture)) return; - - RankingFuture future = (RankingFuture) message.obj; - future.run(); - try { - NotificationRecord record = future.get(); - synchronized (mNotificationList) { - int before = mNotificationList.indexOf(record); - if (before != -1) { - Collections.sort(mNotificationList, mRankingComparator); - int after = mNotificationList.indexOf(record); - - if (before != after) { - scheduleSendRankingUpdate(); - } - } + if (!(message.obj instanceof RankingReconsideration)) return; + RankingReconsideration recon = (RankingReconsideration) message.obj; + recon.run(); + boolean orderChanged; + synchronized (mNotificationList) { + final NotificationRecord record = mNotificationsByKey.get(recon.getKey()); + if (record == null) { + return; } - } catch (InterruptedException e) { - // we're running the future explicitly, so this should never happen - } catch (ExecutionException e) { - // we're running the future explicitly, so this should never happen + int before = findNotificationRecordIndexLocked(record); + recon.applyChangesLocked(record); + Collections.sort(mNotificationList, mRankingComparator); + int after = findNotificationRecordIndexLocked(record); + orderChanged = before != after; + } + if (orderChanged) { + scheduleSendRankingUpdate(); } } + // lock on mNotificationList + private int findNotificationRecordIndexLocked(NotificationRecord target) { + return Collections.binarySearch(mNotificationList, target, mRankingComparator); + } + private void scheduleSendRankingUpdate() { mHandler.removeMessages(MESSAGE_SEND_RANKING_UPDATE); Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE); @@ -2120,11 +2115,11 @@ public class NotificationManagerService extends SystemService { if (r.getNotification().icon != 0) { final long identity = Binder.clearCallingIdentity(); try { - mStatusBar.removeNotification(r.statusBarKey); + mStatusBar.removeNotification(r.getKey()); } finally { Binder.restoreCallingIdentity(identity); } - r.statusBarKey = null; + r.isCanceled = true; mListeners.notifyRemovedLocked(r.sbn, cloneNotificationListLocked()); } @@ -2392,6 +2387,18 @@ public class NotificationManagerService extends SystemService { return -1; } + // lock on mNotificationList + int indexOfNotificationLocked(String key) { + NotificationRecord r = mNotificationsByKey.get(key); + if (r == null) { + return -1; + } + int index = Collections.binarySearch(mNotificationList, r, mRankingComparator); + // Guarantee to return -1 when not found. + return (index >= 0) ? index : -1; + } + + private void updateNotificationPulse() { synchronized (mNotificationList) { updateLightsLocked(); diff --git a/services/core/java/com/android/server/notification/NotificationSignalExtractor.java b/services/core/java/com/android/server/notification/NotificationSignalExtractor.java index a41fdfe..71c819e 100644 --- a/services/core/java/com/android/server/notification/NotificationSignalExtractor.java +++ b/services/core/java/com/android/server/notification/NotificationSignalExtractor.java @@ -18,6 +18,8 @@ package com.android.server.notification; import android.content.Context; +import com.android.server.notification.NotificationManagerService.NotificationRecord; + /** * Extracts signals that will be useful to the {@link NotificationComparator} and caches them * on the {@link NotificationManagerService.NotificationRecord} object. These annotations will @@ -32,10 +34,10 @@ public interface NotificationSignalExtractor { * Called once per notification that is posted or updated. * * @return null if the work is done, or a future if there is more to do. The - * {@link RankingFuture} will be run on a worker thread, and if notifications are re-ordered - * by that execution, the {@link NotificationManagerService} may send order update - * events to the {@link android.service.notification.NotificationListenerService}s. + * {@link RankingReconsideration} will be run on a worker thread, and if notifications + * are re-ordered by that execution, the {@link NotificationManagerService} may send order + * update events to the {@link android.service.notification.NotificationListenerService}s. */ - public RankingFuture process(NotificationManagerService.NotificationRecord notification); + public RankingReconsideration process(NotificationRecord notification); } diff --git a/services/core/java/com/android/server/notification/RankingFuture.java b/services/core/java/com/android/server/notification/RankingReconsideration.java index d711d02..cf5e210 100644 --- a/services/core/java/com/android/server/notification/RankingFuture.java +++ b/services/core/java/com/android/server/notification/RankingReconsideration.java @@ -15,14 +15,16 @@ */ package com.android.server.notification; -import java.util.concurrent.Delayed; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ScheduledFuture; +import com.android.server.notification.NotificationManagerService.NotificationRecord; + import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -public abstract class RankingFuture - implements ScheduledFuture<NotificationManagerService.NotificationRecord> { +/** + * Represents future work required to extract signals from notifications for ranking. + * + * {@hide} + */ +public abstract class RankingReconsideration implements Runnable { private static final long IMMEDIATE = 0l; private static final int START = 0; @@ -32,18 +34,22 @@ public abstract class RankingFuture private int mState; private long mDelay; - protected NotificationManagerService.NotificationRecord mRecord; + protected String mKey; - public RankingFuture(NotificationManagerService.NotificationRecord record) { - this(record, IMMEDIATE); + public RankingReconsideration(String key) { + this(key, IMMEDIATE); } - public RankingFuture(NotificationManagerService.NotificationRecord record, long delay) { + public RankingReconsideration(String key, long delay) { mDelay = delay; - mRecord = record; + mKey = key; mState = START; } + public String getKey() { + return mKey; + } + public void run() { if (mState == START) { mState = RUNNING; @@ -57,18 +63,10 @@ public abstract class RankingFuture } } - @Override public long getDelay(TimeUnit unit) { return unit.convert(mDelay, TimeUnit.MILLISECONDS); } - @Override - public int compareTo(Delayed another) { - return Long.compare(getDelay(TimeUnit.MILLISECONDS), - another.getDelay(TimeUnit.MILLISECONDS)); - } - - @Override public boolean cancel(boolean mayInterruptIfRunning) { if (mState == START) { // can't cancel if running or done mState = CANCELLED; @@ -77,42 +75,25 @@ public abstract class RankingFuture return false; } - @Override public boolean isCancelled() { return mState == CANCELLED; } - @Override public boolean isDone() { return mState == DONE; } - @Override - public NotificationManagerService.NotificationRecord get() - throws InterruptedException, ExecutionException { - while (!isDone()) { - synchronized (this) { - this.wait(); - } - } - return mRecord; - } - - @Override - public NotificationManagerService.NotificationRecord get(long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, TimeoutException { - long timeoutMillis = unit.convert(timeout, TimeUnit.MILLISECONDS); - long start = System.currentTimeMillis(); - long now = System.currentTimeMillis(); - while (!isDone() && (now - start) < timeoutMillis) { - try { - wait(timeoutMillis - (now - start)); - } catch (InterruptedException e) { - now = System.currentTimeMillis(); - } - } - return mRecord; - } - + /** + * Analyse the notification. This will be called on a worker thread. To + * avoid concurrency issues, do not use held references to modify the + * {@link NotificationRecord}. + */ public abstract void work(); + + /** + * Apply any computed changes to the notification record. This method will be + * called on the main service thread, synchronized on he mNotificationList. + * @param record The locked record to be updated. + */ + public abstract void applyChangesLocked(NotificationRecord record); } diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java index b5c2730..157d749 100644 --- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java +++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java @@ -59,7 +59,7 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { // maps raw person handle to resolved person object private LruCache<String, LookupResult> mPeopleCache; - private RankingFuture validatePeople(NotificationRecord record) { + private RankingReconsideration validatePeople(final NotificationRecord record) { float affinity = NONE; Bundle extras = record.getNotification().extras; if (extras == null) { @@ -99,11 +99,11 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { } if (DEBUG) Slog.d(TAG, "Pending: future work scheduled for: " + record.sbn.getKey()); - return new RankingFuture(record) { + return new RankingReconsideration(record.getKey()) { + float mContactAffinity = NONE; @Override public void work() { - if (INFO) Slog.i(TAG, "Executing: validation for: " + mRecord.sbn.getKey()); - float affinity = NONE; + if (INFO) Slog.i(TAG, "Executing: validation for: " + record.getKey()); for (final String handle: pendingLookups) { LookupResult lookupResult = null; final Uri uri = Uri.parse(handle); @@ -124,13 +124,16 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { synchronized (mPeopleCache) { mPeopleCache.put(handle, lookupResult); } - affinity = Math.max(affinity, lookupResult.getAffinity()); + mContactAffinity = Math.max(mContactAffinity, lookupResult.getAffinity()); } } - float affinityBound = mRecord.getContactAffinity(); - affinity = Math.max(affinity, affinityBound); - mRecord.setContactAffinity(affinity); - if (INFO) Slog.i(TAG, "final affinity: " + affinity); + } + + @Override + public void applyChangesLocked(NotificationRecord operand) { + float affinityBound = operand.getContactAffinity(); + operand.setContactAffinity(Math.max(mContactAffinity, affinityBound)); + if (INFO) Slog.i(TAG, "final affinity: " + operand.getContactAffinity()); } }; } @@ -229,7 +232,7 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { mContext.getContentResolver(), SETTING_ENABLE_PEOPLE_VALIDATOR, 1); } - public RankingFuture process(NotificationManagerService.NotificationRecord record) { + public RankingReconsideration process(NotificationRecord record) { if (!mEnabled) { if (INFO) Slog.i(TAG, "disabled"); return null; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 0fa0b14..b06b090 100755 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -6140,7 +6140,12 @@ public class PackageManagerService extends IPackageManager.Stub { } final String nativeLibraryPath = (new File(libDir, apkName)).getPath(); pkg.applicationInfo.nativeLibraryDir = nativeLibraryPath; - pkgSetting.nativeLibraryPathString = nativeLibraryPath; + // pkgSetting might be null during rescan following uninstall of updates + // to a bundled app, so accommodate that possibility. The settings in + // that case will be established later from the parsed package. + if (pkgSetting != null) { + pkgSetting.nativeLibraryPathString = nativeLibraryPath; + } } // Deduces the required ABI of an upgraded system app. diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index 4f75189..8d905ba 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -23,7 +23,7 @@ import android.service.notification.StatusBarNotification; public interface StatusBarManagerInternal { void setNotificationDelegate(NotificationDelegate delegate); - IBinder addNotification(StatusBarNotification notification); - void updateNotification(IBinder key, StatusBarNotification notification); - void removeNotification(IBinder key); + void addNotification(StatusBarNotification notification); + void updateNotification(StatusBarNotification notification); + void removeNotification(String key); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 8b8c73d..55b5e3b 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -60,8 +60,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub private NotificationDelegate mNotificationDelegate; private volatile IStatusBar mBar; private StatusBarIconList mIcons = new StatusBarIconList(); - private HashMap<IBinder,StatusBarNotification> mNotifications - = new HashMap<IBinder,StatusBarNotification>(); + private HashMap<String,StatusBarNotification> mNotifications + = new HashMap<String,StatusBarNotification>(); // for disabling the status bar private final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>(); @@ -117,30 +117,29 @@ public class StatusBarManagerService extends IStatusBarService.Stub } @Override - public IBinder addNotification(StatusBarNotification notification) { + public void addNotification(StatusBarNotification notification) { synchronized (mNotifications) { - IBinder key = new Binder(); - mNotifications.put(key, notification); + mNotifications.put(notification.getKey(), notification); if (mBar != null) { try { - mBar.addNotification(key, notification); + mBar.addNotification(notification); } catch (RemoteException ex) { } } - return key; } } @Override - public void updateNotification(IBinder key, StatusBarNotification notification) { + public void updateNotification(StatusBarNotification notification) { synchronized (mNotifications) { + String key = notification.getKey(); if (!mNotifications.containsKey(key)) { throw new IllegalArgumentException("updateNotification key not found: " + key); } - mNotifications.put(key, notification); + mNotifications.put(notification.getKey(), notification); if (mBar != null) { try { - mBar.updateNotification(key, notification); + mBar.updateNotification(notification); } catch (RemoteException ex) { } } @@ -148,7 +147,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } @Override - public void removeNotification(IBinder key) { + public void removeNotification(String key) { synchronized (mNotifications) { final StatusBarNotification n = mNotifications.remove(key); if (n == null) { @@ -512,8 +511,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub // ================================================================================ @Override public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList, - List<IBinder> notificationKeys, List<StatusBarNotification> notifications, - int switches[], List<IBinder> binders) { + List<StatusBarNotification> notifications, int switches[], List<IBinder> binders) { enforceStatusBarService(); Slog.i(TAG, "registerStatusBar bar=" + bar); @@ -522,9 +520,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub iconList.copyFrom(mIcons); } synchronized (mNotifications) { - for (Map.Entry<IBinder,StatusBarNotification> e: mNotifications.entrySet()) { - notificationKeys.add(e.getKey()); - notifications.add(e.getValue()); + for (StatusBarNotification sbn : mNotifications.values()) { + notifications.add(sbn); } } synchronized (mLock) { @@ -714,7 +711,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub synchronized (mNotifications) { int i=0; pw.println("Notification list:"); - for (Map.Entry<IBinder,StatusBarNotification> e: mNotifications.entrySet()) { + for (Map.Entry<String,StatusBarNotification> e: mNotifications.entrySet()) { pw.printf(" %2d: %s\n", i, e.getValue().toString()); i++; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 1a0dd82..6fbb39d 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -10265,6 +10265,10 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.lockNow(options); } + public void showRecentApps() { + mPolicy.showRecentApps(); + } + @Override public boolean isSafeModeEnabled() { return mSafeMode; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 4e4d127..5395f60 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -3351,6 +3351,44 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override + public UserHandle createUser(ComponentName who, String name) { + synchronized (this) { + if (who == null) { + throw new NullPointerException("ComponentName is null"); + } + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + + long id = Binder.clearCallingIdentity(); + try { + UserInfo userInfo = mUserManager.createUser(name, 0 /* flags */); + if (userInfo != null) { + return userInfo.getUserHandle(); + } + return null; + } finally { + restoreCallingIdentity(id); + } + } + } + + @Override + public boolean removeUser(ComponentName who, UserHandle userHandle) { + synchronized (this) { + if (who == null) { + throw new NullPointerException("ComponentName is null"); + } + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + + long id = Binder.clearCallingIdentity(); + try { + return mUserManager.removeUser(userHandle.getIdentifier()); + } finally { + restoreCallingIdentity(id); + } + } + } + + @Override public Bundle getApplicationRestrictions(ComponentName who, String packageName) { final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId()); diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java index 6ad01a0..0f4e122 100644 --- a/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java +++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java @@ -302,6 +302,36 @@ public abstract class DisplayModifier { paint.setShader(ResourceModifiers.instance().mVertGradient); } }); + put("radGradient", new DisplayModifier() { + @Override + public void modifyDrawing(Paint paint, Canvas canvas) { + paint.setShader(ResourceModifiers.instance().mRadGradient); + } + }); + put("sweepGradient", new DisplayModifier() { + @Override + public void modifyDrawing(Paint paint, Canvas canvas) { + paint.setShader(ResourceModifiers.instance().mSweepGradient); + } + }); + put("composeShader", new DisplayModifier() { + @Override + public void modifyDrawing(Paint paint, Canvas canvas) { + paint.setShader(ResourceModifiers.instance().mComposeShader); + } + }); + put("bad composeShader", new DisplayModifier() { + @Override + public void modifyDrawing(Paint paint, Canvas canvas) { + paint.setShader(ResourceModifiers.instance().mBadComposeShader); + } + }); + put("bad composeShader 2", new DisplayModifier() { + @Override + public void modifyDrawing(Paint paint, Canvas canvas) { + paint.setShader(ResourceModifiers.instance().mAnotherBadComposeShader); + } + }); } }); diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java index c705443..d522481 100644 --- a/tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java +++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java @@ -23,7 +23,11 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapShader; import android.graphics.Color; +import android.graphics.ComposeShader; import android.graphics.LinearGradient; +import android.graphics.PorterDuff; +import android.graphics.RadialGradient; +import android.graphics.SweepGradient; import android.graphics.Matrix; import android.graphics.Shader; @@ -38,6 +42,11 @@ public class ResourceModifiers { public final LinearGradient mHorGradient; public final LinearGradient mDiagGradient; public final LinearGradient mVertGradient; + public final RadialGradient mRadGradient; + public final SweepGradient mSweepGradient; + public final ComposeShader mComposeShader; + public final ComposeShader mBadComposeShader; + public final ComposeShader mAnotherBadComposeShader; public final Bitmap mBitmap; private final Matrix mMtx1; private final Matrix mMtx2; @@ -90,6 +99,12 @@ public class ResourceModifiers { mVertGradient = new LinearGradient(0.0f, 0.0f, 0.0f, mDrawHeight / 2.0f, Color.YELLOW, Color.MAGENTA, Shader.TileMode.MIRROR); + mSweepGradient = new SweepGradient(mDrawWidth / 2.0f, mDrawHeight / 2.0f, + Color.YELLOW, Color.MAGENTA); + + mComposeShader = new ComposeShader(mRepeatShader, mHorGradient, + PorterDuff.Mode.MULTIPLY); + final float width = mBitmap.getWidth() / 8.0f; final float height = mBitmap.getHeight() / 8.0f; @@ -106,6 +121,16 @@ public class ResourceModifiers { 0xff00ff00, 0xff0000ff, 0xffff0000, 0xff00ff00, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00ff0000, }; + + // Use a repeating gradient with many colors to test the non simple case. + mRadGradient = new RadialGradient(mDrawWidth / 4.0f, mDrawHeight / 4.0f, 4.0f, + mBitmapColors, null, Shader.TileMode.REPEAT); + + mBadComposeShader = new ComposeShader(mRadGradient, mComposeShader, + PorterDuff.Mode.MULTIPLY); + + mAnotherBadComposeShader = new ComposeShader(mRadGradient, mVertGradient, + PorterDuff.Mode.MULTIPLY); } } |